#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <algorithm>
#include <assert.h>

#include "game_log.h"
#include "room.h"
#include "player.h"
#include "proto.h"
#include "game_redis.h"
#include "game_server.h"
#include "form_mjs.h"


void Room::stopalltimer()
{
	_dissolution_confirm_timer.stop();
	_hu_flash_timer.stop();
	_ding_que_timer.stop();
	_start_flash_timer.stop();
	_end_flash_timer.stop();
}

void Room::SendError(int uid, int err_code, const string & err_msg)
{
	int fd = YXJMJ_SERVER.Find<UID_KEY>(uid);
	auto session = YXJMJ_SERVER[fd];
	YXJMJ_SERVER.SendError(session, err_code, err_msg);
}

Room::Room(int id) :
	AsyncTimer(YXJMJ_SERVER._base),
	_gm(0),
	_match_id(0),
	_isdissolution(0),
	_clubid(0),
	_priv_uid(0),
	_password(0),
	_roomid(id),
	_has_timer(true),
	_final_user_in_time(0)
{

	InitTimer(_hu_flash_timer, 1, [this]() {
		GAME_LOG.debug("hu_mj_timer_out.\n");
		_hu_flash_timer.stop();
		game_end(0);
	});
}

Room::~Room()
{
	//stopalltimer();
}

int Room::Dispatch(NetworkSessionBase * session, int uid)
{
	//游戏业务协议
	static std::map<int, int(Room::*)(Player *, NetworkSessionBase*)> _game_route =
	{
		{ CLIENT_DISSOLUTION_ROOM_REQ ,&Room::handler_player_dissolution_room_req },
		{ CLIENT_DISSOLUTION_ROOM_CONFIRM ,&Room::handler_player_dissolution_room_confirm },
		{ CLIENT_READY_REQ ,&Room::handler_player_ready },
		{ CLIENT_NOLMAL_CHART_REQ ,&Room::handler_nolmal_chart_req },
		{ CLIENT_SPEAK_REQ ,&Room::handler_speak_req },
		{ CLIENT_DING_QUE_REQ ,&Room::handler_ding_que_req },
		{ CLIENT_BAO_TING_REQ ,&Room::handler_bao_ting_req },
		{ CLIENT_GOLDROOM_LOGOUT_ROOM ,&Room::handler_del_player }
	};

	//游戏玩法协议
	static std::map<int, int(Room::*)(Player *, NetworkSessionBase*)> _game_start_route =
	{
		{ CLIENT_ANG_GANG_REQ ,&Room::handler_player_operater_ANG_GANG },
		{ CLIENT_MING_GANG_REQ ,&Room::handler_player_operater_MING_GANG },
		{ CLIENT_ZIMO_HU_REQ ,&Room::handler_player_operater_ZI_MO },
		{ CLIENT_OUT_MJ_REQ ,&Room::handler_player_operater_PUTOUT_MJ },
		{ CLIENT_PENG_REQ ,&Room::handler_player_operater_PENG },
		{ CLIENT_FANG_GANG_REQ ,&Room::handler_player_operater_FANG_GANG },
		{ CLIENT_FANG_PAO_HU_REQ ,&Room::handler_player_operater_FANG_PAO_HU },
		{ CLIENT_QIANG_GANG_HU_REQ ,&Room::handler_player_operater_QIANG_GANG_HU },
		{ CLIENT_PASS_REQ ,&Room::handler_player_operater_PASS },
		{ CLIENT_PASS2_REQ ,&Room::handler_player_operater_PASS2 },
		{ CLIENT_CANCEL_ROBOT_OP_REQ ,&Room::handler_cancel_robot_op },
		{ CLIENT_ROBOT_AUTO_OUT_MJ_REQ ,&Room::handler_robot_auto_out_mj }
	};
	int cmd = JsonTo<int>(session->_jpacket["cmd"]);
	auto player_itr = _players.find(uid);
	if (player_itr == _players.end())
	{
		return -1;
	}
	auto player = player_itr->second;
	//筛选游戏协议
	auto game_itr = _game_route.find(cmd);
	if (game_itr != _game_route.end())
	{
		auto func = game_itr->second;
		(this->*func)(player,session);
		return 0;
	}
	//筛选游戏内部指令，必须游戏开始状态下使用
	game_itr = _game_start_route.find(cmd);
	if (game_itr != _game_start_route.end() && _state == STATE_PLAYING)
	{
		auto func = game_itr->second;
		(this->*func)(player, session);
		return 0;
	}
	else
	{
		GAME_LOG.error("invalid command[%d] state[%d]\n", cmd, _state);
		return -1;
	}
	return 0;
}

bool Room::check(void* p_choose_rule/*筛选规则*/)
{
	RoomChooseRule* choose_rule = (RoomChooseRule*)p_choose_rule;
	if (_state != STATE_READY)
	{
		return false;
	}
	if (choose_rule->_robot_in_wait_sec != 0)
	{
		//不能进入没有一个正常用户的房间，有正常用户也不能马上进去
		int real_player_num(0);
		for (auto &player : _players)
		{
			if (player.second->_robot_flag == 0)
			{
				real_player_num++;
			}
		}
		//新的机器人 要在上一个人进去robot_in_wait_sec秒后，才能进去
		if (real_player_num == 0 || (choose_rule->_robot_in_wait_sec + _final_user_in_time) > time(NULL))
		{
			return false;
		}
	}
	//如果是快抢赛
	if (YXJMJ_SERVER._game_flag / 1000000 == 3)
	{
		if (choose_rule->_robot_in_wait_sec != 0 && _match_id != 0)
		{
			return true;
		}
		else if (choose_rule->_match_id == 0)
		{
			return false;
		}
		else if (!_players.empty())
		{
			//如果是同一个快抢赛
			return (_match_id == choose_rule->_match_id);
		}
	}
	return true;
}

void Room::init()
{
	//如果是匹配场
	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		if (init_gold_room(YXJMJ_SERVER._min_access
			, YXJMJ_SERVER._max_access
			, YXJMJ_SERVER._tai_fee
			, YXJMJ_SERVER._base_gold) < 0)
		{
			GAME_LOG.error("gold room[%d] init err\n", _roomid);
			exit(1);
		}
	}
}


int Room::init_private(int my_board_choose, int my_player_num)
{
	//roomid = my_roomid;
	_board_choose = my_board_choose;
	_player_num = my_player_num;

	for (int i = 0; i < 4; i++)
	{
		_seats[i]._seat_no = i;
		_seats[i]._occupied = false;
		_seats[i]._player = NULL;
	}

	_next_banker_seat = 0;
	_rest_board = _board_choose;

	_dice[0] = 0;
	_dice[1] = 0;
	_state = STATE_READY;

	_rec_id = -1;
	return 0;
}

int Room::init_gold_room(int min_access_gold, int max_access_gold, int tai_fee, int base_gold)
{
	//roomid = _i;
	_min_access_gold = min_access_gold;
	_max_access_gold = max_access_gold;
	_tai_fee = tai_fee;
	_base_gold = base_gold;

	_player_num = 4;

	for (int i = 0; i < _player_num; i++)
	{
		_seats[i]._seat_no = i;
		_seats[i]._occupied = false;
		_seats[i]._player = NULL;
	}

	_next_banker_seat = 0;
	_rest_board = _board_choose;

	_dice[0] = 0;
	_dice[1] = 0;
	_state = STATE_READY;

	_rec_id = -1;

	return 0;
}


int Room::reset_shop_match(int choose)
{
	_board_choose = choose;
	_rest_board = _board_choose;
	return 0;
}

void Room::reset()
{
	_gang_shang_pao_check_flag = 0;
	_cur_outmj_player = NULL;
	_cur_outmj.val = 0;
	_cur_qgh_player = NULL;
	_cur_qgh_mj.val = 0;
	_cur_getin_player = NULL;
	_cur_getin_mj = 0;
	_end_type = 0;
	_gang_mo_cnt = 0;
	_banker_seat = _next_banker_seat;
	_fangpaiji_mj.val = 0;
	_chongfengji_player = NULL;    //冲锋鸡玩家指针
	_zherenji_from_player = NULL;  //打出 责任鸡玩家 
	_zherenji_to_player = NULL;    //碰了凑成 责任鸡玩家	
	_zherenji_type = 3;
	_dice[0] = 0;
	_dice[1] = 0;
}


int Room::player_enter_room(Player *player)
{
	//不是准备状态下是不能进去的
	if (_state != STATE_READY)
	{
		GAME_LOG.error("join_room_add_player, state must[%d] STATE_READY, now state[%d].\n", STATE_READY, _state);
		SendError(player->_uid, 55, "游戏已经开始");
		return -1;
	}
	//房间坐不下了
	if ((int)_players.size() >= _player_num)
	{
		SendError(player->_uid, 55, "房间人数已满");
		return -1;
	}
	//用户已经在房间里面了
	if (_players.find(player->_uid) != _players.end())
	{
		GAME_LOG.error("handler_join_table uid[%d] is in room[%d]\n", player->_uid, player->_roomid);
		return -1;
	}
	//坐下
	player->_seatid = sit_down(player);
	if (player->_seatid < 0)
	{
		GAME_LOG.error("room_add_player, player[%d], sit_down error.\n", player->_uid);
		return -1;
	}
	_players[player->_uid] = player;
	player->_roomid = _roomid;
	//修改用户状态
	//player->client->set_positon(POSITION_TABLE);
	int auto_ready = (YXJMJ_SERVER._default_db.find("migu") == std::string::npos) ? 1 : 0;
	GAME_LOG.debug("auto_ready = %d\n", auto_ready);
	auto_ready = (player->_robot_flag == 1) ? 1 : auto_ready;
	if (auto_ready == 1)
	{
		player->_status = READY;
	}
	else
	{
		player->_status = NOT_READY;
		if (_has_timer)player->_ready_timer.start();
	}
	//把用户加入在线列表
	//YXJMJ_SERVER._server->online_players[player->_uid] = player;
	//将用户进入了哪个房间刷入数据库
	if (game_sql::update_db_player_online(player->_uid, YXJMJ_SERVER._server_id, player->_roomid, 1) < 0)
	{
		GAME_LOG.fatal("player_enter_room, update db error.\n");
	}
	//发送进入房间报文
	JsonPacket packet;
	packet["cmd"] = SERVER_ENTER_ROOM_UC;
	packet["game_flag"] = YXJMJ_SERVER._game_flag;
	packet["roomid"] = _roomid;
	packet["room_pwd"] = _password;
	packet["uid"] = player->_uid;
	packet["board_choose"] = _board_choose;
	packet["seatid"] = player->_seatid;
	packet["player_num"] = _player_num;
	packet["gold"] = player->_gold;
	packet["clubid"] = _clubid;
	packet["priv_uid"] = _priv_uid;
	GAME_LOG.debug("SERVER_ENTER_ROOM_UC.\n");
	unicast(player, packet);
	//通知现在房间里面的所有人-其它人的信息
	table_info_broadcast();
	if (auto_ready == 1)
	{
		if (0 == judge_game_start())
		{
			start_game();
		}
	}
	_final_user_in_time = time(NULL);
	return 0;
}


int Room::sit_down(Player *player)
{
	for (int i = 0; i < _player_num; i++)
	{
		if (!_seats[i]._occupied)
		{
			_seats[i]._occupied = true;
			_seats[i]._player = player;
			return i;
		}
	}
	return -1;
}

void Room::stand_up(Player *player)
{
	_seats[player->_seatid]._occupied = false;
	_seats[player->_seatid]._player = NULL;
}

Player * Room::GetPlayer(int uid)
{
	auto itr = _players.find(uid);
	if (itr == _players.end())
	{
		return nullptr;
	}
	return itr->second;
}


int Room::table_info_broadcast()
{
	JsonPacket packet;
	packet["cmd"] = SERVER_ROOM_INFO_BC;

	packet["game_flag"] = YXJMJ_SERVER._game_flag;
	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		packet["base_gold"] = _base_gold;
		packet["min_access_gold"] = _min_access_gold;
		packet["max_access_gold"] = _max_access_gold;
		packet["tai_fee"] = _tai_fee;
	}

	packet["roomid"] = _roomid;
	packet["board_choose"] = _board_choose;
	packet["player_num"] = _player_num;
	packet["rest_board"] = _rest_board;
	packet["status"] = _state;
	for (auto& info : _players)
	{
		auto p = info.second;
		Json::Value pinfo;
		pinfo["uid"] = p->_uid;
		pinfo["seatid"] = p->_seatid;
		pinfo["nick_name"] = p->_nick_name;
		pinfo["avater_url"] = p->_avater_url;
		pinfo["login_ip"] = p->_login_ip;
		pinfo["score"] = p->_score;
		pinfo["sex"] = p->_sex;
		pinfo["gold"] = p->_gold;
		pinfo["diamonds"] = p->_diamonds;
		pinfo["status"] = p->_status;
		pinfo["online"] = p->_online;
		pinfo["paiwei_score"] = p->_paiwei_score;
		pinfo["vip_level"] = p->_vip_level;
		packet["players"].append(pinfo);
	}
	GAME_LOG.debug("SERVER_ROOM_INFO_BC.\n");
	broadcast(NULL, packet);
	return 0;
}

int Room::start_ready()
{
	if (YXJMJ_SERVER._game_flag < 1000000)
	{
		if (_rest_board != 0)
		{
			JsonPacket packet;
			packet["cmd"] = SERVER_GAME_READY_STAGE_BC;
			packet["roomid"] = _roomid;
			GAME_LOG.debug("SERVER_GAME_READY_STAGE_BC.\n");
			broadcast(NULL, packet);

			for (auto& info : _players)
			{
				info.second->reset();
			}
			_state = STATE_READY;
		}
		else
		{
			do_dissolution_room();
		}
		return 0;
	}
	else if (YXJMJ_SERVER._game_flag > 3000000)
	{
		if (_rest_board != 0)
		{
			JsonPacket packet;
			packet["cmd"] = SERVER_GAME_READY_STAGE_BC;
			packet["roomid"] = _roomid;
			packet["expire"] = (YXJMJ_SERVER._game_flag / 1000000 == 3) ? 30 : 15;
			GAME_LOG.debug("SERVER_GAME_READY_STAGE_BC.\n");
			broadcast(NULL, packet);

			for (auto pinfo : _players)
			{
				Player *player = pinfo.second;
				player->reset();
				player->_ready_timer.start();
			}
			_state = STATE_READY;
		}
		else
		{
			_state = STATE_READY;
			del_all_players();
		}
		return 0;
	}
	else
	{
		JsonPacket packet;
		packet["cmd"] = SERVER_GAME_READY_STAGE_BC;
		packet["roomid"] = _roomid;
		packet["expire"] = (YXJMJ_SERVER._game_flag / 1000000 == 3) ? 30 : 15;
		GAME_LOG.debug("SERVER_GAME_READY_STAGE_BC.\n");
		broadcast(NULL, packet);

		_state = STATE_READY;

		vector<int>	die_player;				//要被杀死的临时数组
		//连接断开和钱钱不够的都干掉
		for (auto& info : _players)
		{
			auto p = info.second;
			if (-1 == YXJMJ_SERVER.Find<UID_KEY>(info.first))
			{
				die_player.push_back(info.first);
				p->_logout_type = 1;
			}
			else if (YXJMJ_SERVER._game_flag == 2000001 && p->_diamonds <= _min_access_gold && p->_robot_flag == 0)
			{
				die_player.push_back(info.first);
				p->_logout_type = 2;
			}
			else if (YXJMJ_SERVER._game_flag != 2000001 && p->_gold <= _min_access_gold && p->_robot_flag == 0)
			{
				die_player.push_back(info.first);
				p->_logout_type = 2;
			}
		}
		//真正的干掉
		for (auto& uid : die_player)
		{
			del_player(uid);
		}
		//剩下的用户重置状态并准备计时打开
		for (auto& info : _players)
		{
			auto player = info.second;
			player->reset();
			player->_ready_timer.start();
		}
	}

	return 0;
}



int Room::start_game()
{
	reset();
	_rest_board--;
	GAME_LOG.debug("\n#########################start_game: #### rest_board:%d.\n", _rest_board);
	//是金币场或者排位场
	if (YXJMJ_SERVER._game_flag > 1000000 && YXJMJ_SERVER._game_flag < 3000000)
	{
		for (int i = 0; i<_player_num; i++)
		{
			if (_seats[i]._player->_robot_flag != 0)
			{
				continue;
			}
			int uid = _seats[i]._player->_uid;

			if (YXJMJ_SERVER._game_flag == 2000001)
			{
				game_sql::decrease_diamonds(uid, -10);
				game_sql::insert_diamonds_change_rec(uid, -10, "台费", "排位场扣除台费");
				_seats[i]._player->_diamonds -= 10;
				GAME_LOG.debug("####uid:%d,  diamonds:%d \n", uid, _seats[i]._player->_diamonds);
			}
			else
			{
				game_sql::decrease_gold(uid, -_tai_fee);
				game_sql::insert_gold_change_rec(uid, -_tai_fee, "台费", "金币场扣除台费");
				_seats[i]._player->_gold -= _tai_fee;
				GAME_LOG.debug("####uid:%d,  gold:%d \n", uid, _seats[i]._player->_gold);
			}
		}
	}

	_deck.fill();
	bool gm = false;
	if (_gm != 0 && _gm_vec.size() == 13)
	{
		gm = _deck.catch_spec(_gm_vec);
	}
	_deck.shuffle(_roomid);
	_cur_seat = _banker_seat;

	for (int i = 0; i<_player_num; i++)
	{
		if (gm == true && _seats[i]._player->_uid == _gm)
		{
			_seats[i]._player->_hole_mjs.mjs = _gm_vec;
			continue;
		}
		_deck.get_player_hole_mjs(_seats[i]._player->_hole_mjs);
	}
	_gm_vec.clear();
	_gm = 0;

	srand(time(NULL));
	_dice[0] = (rand() + _roomid) % 6 + 1;
	_dice[1] = (rand() + _roomid) % 6 + 1;

	_deck.get_common_mjs(_comm_mjs);
	JsonPacket packet;
	packet["cmd"] = SERVER_GAME_START_BC;
	packet["banker_seatid"] = _banker_seat;
	packet["roomid"] = _roomid;
	packet["rest_mjs"] = _comm_mjs.count();
	packet["rest_board"] = _rest_board;
	packet["dice"].append(_dice[0]);
	packet["dice"].append(_dice[1]);
	for (int i = 0; i<_player_num; i++)
	{
		Player *p = _seats[i]._player;
		packet["players"][i]["uid"] = p->_uid;
		packet["players"][i]["seatid"] = p->_seatid;
		packet["players"][i]["diamonds"] = p->_diamonds;
		packet["players"][i]["gold"] = p->_gold;
		for (unsigned int j = 0; j<p->_hole_mjs.mjs.size(); j++)
		{
			packet["players"][i]["_hole_mjs"].append(p->_hole_mjs.mjs[j].val);
		}
		if (p->_hole_mjs.mjs.size() == 0)
		{
			packet["players"][i]["_hole_mjs"].resize(0);
		}
	}
	GAME_LOG.debug("SERVER_GAME_START_BC.\n");
	broadcast(NULL, packet);

	for (int i = 0; i<_player_num; i++)
	{
		_seats[i]._player->_status = INPlAY;
	}

	_state = STATE_MJ_FLASH;
	//游戏开始动画延时
	RunOnce(_start_flash_timer, 4, [this]() {
		GAME_LOG.debug("mj_flash_timer_out.\n");
		start_play();
	});

	return 0;
}

int Room::start_play()
{
	if (_player_num == 2 || _player_num == 3) //2人场，3人场 需定缺
	{
		_state = STATE_DING_QUE;
		JsonPacket packet;
		packet["cmd"] = SERVER_DINGQUE_STARGE_BC;
		packet["roomid"] = _roomid;
		packet["expire"] = 20;
		GAME_LOG.info("SERVER_DINGQUE_STARGE_BC.\n");
		broadcast(NULL, packet);
		//_ding_que_timer.start();
		RunOnce(_ding_que_timer, 20, [this]() {
			GAME_LOG.debug("din_que_timer_cb.\n");
			//_ding_que_timer.stop();
			robot_do_din_que();
		});
	}
	else //四人场
	{
		start_play_2();
	}

	return 0;
}

int Room::start_play_2()
{
	_state = STATE_PLAYING;
	Player *cur_player = _seats[_cur_seat]._player;
	getin_mj(cur_player);
	return 0;
}

int Room::judge_game_start()
{
	int cnt = 0;
	for (auto& info : _players)
	{
		Player* p = info.second;
		if (p->_status == READY) cnt++;
	}
	if (cnt >= _player_num)
	{
		//如果不是第一局就不用做以下判断
		if (_rest_board != _board_choose)
		{
			return 0;
		}
		if (YXJMJ_SERVER._game_flag / 1000000 == 3)
		{
			_match_reward = game_sql::get_discount_codes(_match_id, _player_num);
			if (_match_reward.size() != _player_num)
			{
				JsonPacket packet;
				packet["cmd"] = SERVER_ERROR_UC;
				packet["err"] = 56;
				packet["err_msg"] = "很遗憾！当前场次的名额已抢完！\n其它场次仍有机会，不要错过哟！";
				GAME_LOG.debug("SERVER_ERROR_UC.\n");
				broadcast(NULL, packet);
				del_all_players();
				return -1;
			}
			set<int> uids;
			for (auto& info : _players)
			{
				if (info.second->_robot_flag == 0)
				{
					uids.insert(info.first);
				}
			}
			if (0 != game_sql::sub_quick_match_count(uids))
			{
				game_sql::return_discount_codes(_match_reward);
				JsonPacket packet;
				packet["cmd"] = SERVER_ERROR_UC;
				packet["err"] = 59;
				packet["err_msg"] = "本快抢赛有非法用户，请重新匹配对手";
				GAME_LOG.debug("SERVER_ERROR_UC.\n");
				broadcast(NULL, packet);
				del_all_players();
				return -1;
			}
		}
		else if (YXJMJ_SERVER._game_flag < 1000000)
		{
			//如果票状态不对 解散房间
			if (0 != game_sql::update_room_ticket_status(_rec_id, 3))
			{
				GAME_LOG.info("SERVER_ENTER_ROOM_UC.\n");
				do_dissolution_room();
				return -1;
			}
			//记录哪些用户在玩了
			std::string time_str = general_time_str();
			if (_player_num == 2) {
				game_sql::insert_total_end_record(_roomid, _board_choose, 0, time_str,
					_seats[0]._player->_uid, 0,
					_seats[1]._player->_uid, 0);
			}
			else if (_player_num == 3) {
				game_sql::insert_total_end_record(_roomid, _board_choose, 0, time_str,
					_seats[0]._player->_uid, 0,
					_seats[1]._player->_uid, 0,
					_seats[2]._player->_uid, 0);
			}
			else if (_player_num == 4) {
				game_sql::insert_total_end_record(_roomid, _board_choose, 0, time_str,
					_seats[0]._player->_uid, 0,
					_seats[1]._player->_uid, 0,
					_seats[2]._player->_uid, 0,
					_seats[3]._player->_uid, 0);
			}
			GAME_LOG.debug("#########ret_id = %d.\n", _rec_id);
		}
		return 0;
	}
	return -1;
}

int Room::handler_ding_que_req(Player *player, NetworkSessionBase* session)
{

	JsonPacket& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	int dq_val = JsonTo<int>(jpacket["dq_val"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_ding_que_req, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (dq_val != 1 && dq_val != 3 && dq_val != 5)  //万，条，筒
	{
		GAME_LOG.error("handler_ding_que_req, dq_val[%d] error.\n", dq_val);
		return -1;
	}
	if (_state != STATE_DING_QUE)
	{
		GAME_LOG.error("handler_ding_que_req, uid[%d], state error, cur state\n", uid, _state);
		return -1;
	}
	if (_player_num == 4)
	{
		GAME_LOG.error("four pepole game, has no ding que stage.\n");
		return -1;
	}

	player->_dq_val = dq_val;

	JsonPacket packet;
	packet["cmd"] = SERVER_DINGQUE_SUCC_BC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["dq_val"] = dq_val;
	GAME_LOG.debug("SERVER_DINGQUE_SUCC_BC.\n");
	broadcast(NULL, packet);

	int cnt = 0;
	for (auto& info : _players)
	{
		if (info.second->_dq_val > 0)cnt++;
	}

	if (cnt >= _player_num)
	{
		_ding_que_timer.stop();

		JsonPacket packet;
		packet["cmd"] = SERVER_ALL_DIN_QUE_SUCC_BC;
		int i = 0;
		for (auto it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			packet["players"][i]["uid"] = p->_uid;
			packet["players"][i]["seatid"] = p->_seatid;
			packet["players"][i]["dq_val"] = p->_dq_val;
			i++;
		}
		broadcast(NULL, packet);

		start_play_2();
	}

	return 0;
}

int Room::robot_do_din_que()
{
	for (auto it = _players.begin(); it != _players.end(); it++)
	{
		Player *player = it->second;
		if (player->_dq_val == 0)
		{
			player->_dq_val = calculate_min_que(player);
			JsonPacket packet;
			packet["cmd"] = SERVER_DINGQUE_SUCC_BC;
			packet["uid"] = player->_uid;
			packet["seatid"] = player->_seatid;
			packet["roomid"] = player->_roomid;
			packet["dq_val"] = player->_dq_val;
			GAME_LOG.debug("SERVER_DINGQUE_SUCC_BC.\n");
			broadcast(NULL, packet);
		}
	}

	JsonPacket packet;
	packet["cmd"] = SERVER_ALL_DIN_QUE_SUCC_BC;
	int i = 0;
	for (auto it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		packet["players"][i]["uid"] = p->_uid;
		packet["players"][i]["seatid"] = p->_seatid;
		packet["players"][i]["dq_val"] = p->_dq_val;
		i++;
	}
	broadcast(NULL, packet);

	start_play_2();
	return 0;
}

int Room::calculate_min_que(Player *player)
{
	std::vector<Mj>::iterator it;
	int c1 = 0, c2 = 0, c3 = 0;
	int dq = 1;
	for (it = player->_hole_mjs.mjs.begin(); it != player->_hole_mjs.mjs.end(); it++)
	{
		Mj mj = *it;
		if (mj.color() == 1) c1++;
		else if (mj.color() == 2) c2++;
		else if (mj.color() == 3) c3++;
	}
	GAME_LOG.debug("uid:%d   c1=%d, c2=%d, c3=%d\n", player->_uid, c1, c2, c3);
	int min = 0;
	min = c1<c2 ? c1 : c2;
	min = c3<min ? c3 : min;

	GAME_LOG.debug("min=%d.\n", min);

	if (min == c1) dq = 1;
	else if (min == c2) dq = 3;
	else if (min == c3) dq = 5;
	GAME_LOG.debug("dq=%d.\n", dq);
	return dq;
}



int Room::handler_player_operater_ANG_GANG(Player *player, NetworkSessionBase* session)
{

	JsonPacket& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, cur_seat[%d], player->_seatid[%d].\n", uid, player->_seatid);
		return -1;
	}

	int anggang_val = JsonTo<int>(jpacket["angang_mj"]);
	//检查是否是合法的麻将牌
	if (!Mj::check_mjval(anggang_val))
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, anggang_val[%d] error.\n", anggang_val);
		return -1;
	}
	Mj mj(anggang_val);
	//杠牌
	if (do_ang_gang(player, mj) < 0)
	{
		GAME_LOG.error("handler_player_operater_ANG_GANG, do anggang error.\n");
		return -1;
	}

	player->_getin_outmj_timer.stop();
	//告诉所有人这个人暗杠了
	JsonPacket packet;
	packet["cmd"] = SERVER_ANGGANG;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	packet["mj"] = anggang_val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_PENG.\n");
	broadcast(NULL, packet);

	_gang_shang_pao_check_flag = ANG_GANG;

	//用户从最后面获得一张麻将牌
	getin_mj(player, 1);

	return 0;
}

int Room::handler_player_operater_MING_GANG(Player *player, NetworkSessionBase* session)
{
	JsonPacket& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	//明杠必须是自己刚抓的
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, cur_seat[%d], player->_seatid[%d].\n", uid, player->_seatid);
		return -1;
	}
	int ming_gang_val = JsonTo<int>(jpacket["ming_gang_mj"]);
	if (!Mj::check_mjval(ming_gang_val))
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, ming_gang_val[%d] error.\n", ming_gang_val);
		return -1;
	}
	//如果这个牌不是刚摸得
	if (player->_mo_mj.val != ming_gang_val)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, player->_mo_mj.val[%d] != ming_gang_val[%d].\n", player->_mo_mj.val, ming_gang_val);
		return -1;
	}

	//停止打牌计时器
	player->_getin_outmj_timer.stop();

	//清空用户的抢杠胡检测
	int c = 0;
	for (auto it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p == player)
		{
			continue;
		}
		P_CHECK_QGH p_check_qgh;
		p_check_qgh.clear();
		p_check_qgh._player = p;
		_m_check_qgh[c] = p_check_qgh;
		c++;
	}

	if (operate_check_qiang_gang_hu(player->_mo_mj, player) == 1) //鏈夊彲浠ユ姠鏉犺儭,鏄庢潬澶辫触
	{
		GAME_LOG.info("handler_player_operater_MING_GANG, but now other can qiang gang hu.\n");
		_cur_qgh_mj = player->_mo_mj;
		_cur_qgh_player = player;
		return 0;
	}
	else
	{
		do_MING_GANG(player);
	}

	return 0;
}

int Room::do_MING_GANG(Player *player)
{
	if (do_ming_gang(player, player->_mo_mj) < 0)
	{
		GAME_LOG.error("handler_player_operater_MING_GANG, _mo_mj[%d].\n", player->_mo_mj.val);
		return -1;
	}
	//是不是责任鸡
	if (player->_mo_mj.val == S1)
	{
		_zherenji_type = 4;
	}
	//通知所有人
	JsonPacket packet;
	packet["cmd"] = SERVER_MINGGANG;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	packet["mj"] = player->_mo_mj.val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_MINGGANG.\n");
	broadcast(NULL, packet);
	_gang_shang_pao_check_flag = MING_GANG;

	//摸牌
	getin_mj(player, 1);

	return 0;
}

int Room::handler_bao_ting_req(Player *player, NetworkSessionBase* session)
{
	JsonPacket& jpacket = session->_jpacket;	
	int uid = JsonTo<int>(jpacket["uid"]);
	int ting_out_mj = JsonTo<int>(jpacket["ting_out_mj"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_bao_ting_req, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_bao_ting_req, cur_seat[%d], player->_seatid[%d].\n", uid, player->_seatid);
		return -1;
	}
	if (!Mj::check_mjval(ting_out_mj))
	{
		GAME_LOG.error("handler_bao_ting_req, outmj_val[%d] error.\n", ting_out_mj);
		return -1;
	}

	//广播消息
	JsonPacket packet;
	packet["cmd"] = SERVER_BAO_TING_SUCC_BC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;

	form_player_all_mj_info_json(player, packet, "mjs_info");

	GAME_LOG.debug("SERVER_BAO_TING_SUCC_BC.\n");
	broadcast(NULL, packet);

	if (do_PUTOUT_MJ(player, ting_out_mj) < 0)
	{
		GAME_LOG.error("handler_bao_ting_req, do_PUTOUT_MJ error.\n");
		return -1;
	}

	player->_cur_baoting_flag = 1;

	//必须首次摸牌
	//1，如果庄家首次摸牌，天听
	if (player->_seatid == _banker_seat && player->_mo_cnt == 1)
	{
		player->_cur_baoting_flag = 1;
	}
	//2, 非庄家，首次摸牌, 地听
	else if (player->_seatid != _banker_seat && player->_mo_cnt == 1)
	{
		player->_cur_baoting_flag = 2;
	}
	else
	{
		GAME_LOG.fatal("handler_bao_ting_req, logic fatal error.\n this fatal must not apper-------- - -! -- ");
		return -1;
	}
	return 0;
}


//自摸胡牌
int Room::do_zi_mo_hu(Player *player)
{
	//是否能胡牌
	if (!check_zi_mo_hu(player))
	{
		GAME_LOG.error("can not zi mo hu, player[%d].\n", player->_uid);
		return -1;
	}
	//停止出牌计时器
	player->_getin_outmj_timer.stop();

	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		//检测是否叫牌
		check_jiaopai_flag(p);
		if (p == player)
		{
			p->_cur_pao_flag = 3; //当前玩家自摸
			p->_cur_end_flag = 2; //当前玩家赢
			continue;
		}
		p->_cur_end_flag = 1; //当前玩家输
	}
	//检测天胡
	if (_comm_mjs.count() == (108 - 13 * _player_num) - 1) //摸的第一张牌，是庄家
	{
		player->_tian_hu_flag = 1;
	}

	if (_gang_shang_pao_check_flag == 0)
	{
		_end_type = ET_ZI_MO;
	}
	else
	{
		_end_type = ET_GANG_KAI_ZI_MO;
	}
	//自摸次数？有何用
	player->_zimo_times++;
	//这局胡牌的人做庄
	_next_banker_seat = player->_seatid;
	return 0;
}

//放炮胡牌
int Room::do_fang_pao_hu(Player *player, Mj mj, Player *out_mj_player)
{
	if (!check_fang_pao_hu(player, mj, out_mj_player))
	{
		GAME_LOG.error("can not fang pao hu mj[%d], player[%d].\n", mj.val, player->_uid);
		return -1;
	}
	player->_hole_mjs.add_mj(mj);

	//是否地胡
	if (_comm_mjs.count() == 108 - _player_num * 13 - 1)
	{
		player->_di_hu_flag = 1;
	}

	player->_card_type = calculate_card_type(player);

	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}

	player->_cur_pao_flag = 2;                    //当前玩家是接炮胡，
	player->_jiepao_times++;

	out_mj_player->_cur_pao_flag = 1;     //玩家是放炮玩家

	out_mj_player->_dianpao_times++;
	player->_cur_end_flag = 2;           //当前玩家赢了
	out_mj_player->_cur_end_flag = 1;    //当前玩家输了

	if (_gang_shang_pao_check_flag == 0)
	{
		_end_type = ET_FANG_PAO;
	}
	else
	{
		_end_type = ET_FANG_RE_PAO;
	}
	_next_banker_seat = player->_seatid;
	return 0;
}


int Room::do_qiang_gang_hu(Player *player, Mj mj, Player *qiang_gang_player)
{
	if (!check_qiang_gang_hu(player, mj, qiang_gang_player))
	{
		GAME_LOG.error("can not do qiang gang hu mj[%d], qiang_gang_player[%d], player[%d].\n", mj.val, qiang_gang_player->_uid, player->_uid);
		return -1;
	}
	player->_hole_mjs.add_mj(mj);
	player->_card_type = calculate_card_type(player);

	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}

	player->_cur_pao_flag = 2; //当前玩家是接炮
	qiang_gang_player->_cur_pao_flag = 1;

	player->_cur_end_flag = 2; //当前玩家赢了
	qiang_gang_player->_cur_end_flag = 1;

	YXJMJ_SERVER._rooms[_roomid]->_end_type = ET_QIANG_GANG;
	YXJMJ_SERVER._rooms[_roomid]->_next_banker_seat = player->_seatid;

	return 0;
}


//计算赢番型
int Room::calculate_card_type(Player *player)
{
	int card_type = CARD_TYPE_PINGHU;
	//是否清一色
	if (!logic_check_qing_yi_se(player->_hole_mjs, player->_form_mjs, player->_out_mjs)) //不是
	{
		int qidui_val = logic_check_qidui(player->_hole_mjs, player->_form_mjs, player->_out_mjs);
		if (qidui_val == 1) //七对
		{
			card_type = CARD_TYPE_QIDUI;
		}
		else if (qidui_val == 2) //龙七对 有一组4个一样的
		{
			card_type = CARD_TYPE_LONGQIDUI;
		}
		else if (logic_check_dandiao(player->_hole_mjs, player->_form_mjs, player->_out_mjs)) //单吊 手上就一张牌在等胡
		{
			card_type = CARD_TYPE_DANDIAO;
		}
		else if (logic_check_pengpenghu(player->_hole_mjs, player->_form_mjs, player->_out_mjs)) //碰碰胡(大对子)
		{
			card_type = CARD_TYPE_DADUIZI;
		}
	}
	else
	{
		card_type = CARD_TYPE_QINGYISE;

		int qidui_val = logic_check_qidui(player->_hole_mjs, player->_form_mjs, player->_out_mjs);
		if (qidui_val == 1) //清一色七对
		{
			card_type = CARD_TYPE_QINGQIDUI;
		}
		else if (qidui_val == 2) //清一色龙七对(清龙背)
		{
			card_type = CARD_TYPE_QINGLONGBEI;
		}
		else if (logic_check_dandiao(player->_hole_mjs, player->_form_mjs, player->_out_mjs)) //清一色单吊
		{
			card_type = CARD_TYPE_DANDIAOQINGYISE;
		}
		else if (logic_check_pengpenghu(player->_hole_mjs, player->_form_mjs, player->_out_mjs)) //清一色碰碰胡(清大对)
		{
			card_type = CARD_TYPE_QINGDADUI;
		}
	}

	if (player->_tian_hu_flag == 1)
	{
		if (card_type < CARD_TYPE_TIANHU)
		{
			card_type = CARD_TYPE_TIANHU;
		}
	}
	else if (player->_di_hu_flag == 1)
	{
		if (card_type < CARD_TYPE_DIHU)
		{
			card_type = CARD_TYPE_DIHU;
		}
	}

	if (player->_cur_baoting_flag == 1 && player->_seatid == _banker_seat)
	{
		if (card_type < CARD_TYPE_TIAN_TING)
		{
			card_type = CARD_TYPE_TIAN_TING;
		}
	}
	else if (player->_cur_baoting_flag == 2 && player->_seatid != _banker_seat)
	{
		if (card_type < CARD_TYPE_DI_TING)
		{
			card_type = CARD_TYPE_DI_TING;
		}
	}
	return card_type;
}

//叫嘴玩家最大胡牌牌型
int Room::check_ting_max_cardtype(Player *player)
{
	if (player->_jiaopai_flag == 0)
		return 0;

	int max_card_type = 0;

	int count = player->_hole_mjs.mjs.size();
	if (count % 3 != 1)
	{
		GAME_LOG.error("check_ting_max_cardtype, v_mjs size error.\n");
		return max_card_type;
	}

	for (int mj_val = S1; mj_val <= S9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->_hole_mjs.mjs;
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->_hole_mjs.mjs.push_back(mj);
		if (check_hupai(mjs_temp, player->_dq_val))
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type)
			{
				max_card_type = card_type;
			}
		}
		player->_hole_mjs.mjs.pop_back();
	}

	for (int mj_val = T1; mj_val <= T9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->_hole_mjs.mjs;
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->_hole_mjs.mjs.push_back(mj);
		if (check_hupai(mjs_temp, player->_dq_val))
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type)
			{
				max_card_type = card_type;
			}

		}
		player->_hole_mjs.mjs.pop_back();


	}

	for (int mj_val = W1; mj_val <= W9; mj_val++)
	{
		std::vector<Mj> mjs_temp = player->_hole_mjs.mjs;
		Mj mj; mj.val = mj_val;
		mjs_temp.push_back(mj);
		player->_hole_mjs.mjs.push_back(mj);
		if (check_hupai(mjs_temp, player->_dq_val))
		{
			int card_type = 0;
			card_type = calculate_card_type(player);
			if (card_type > max_card_type)
			{
				max_card_type = card_type;
			}
		}
		player->_hole_mjs.mjs.pop_back();

	}

	return max_card_type;
}


//叫嘴玩家胡牌牌型(听牌)
int Room::calculate_jiaopai_card_type(Player *player)
{
	if (player->_jiaopai_flag == 0)
		return 0;

	if (player->_hole_mjs.mjs.size() % 3 == 2)
	{
		return calculate_card_type(player);
	}

	if (player->_hole_mjs.mjs.size() % 3 == 1)
	{
		return check_ting_max_cardtype(player);
	}

	return 0;
}



int Room::handler_player_operater_ZI_MO(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, uid[%d],cur_seat[%d], player->_seatid[%d].\n", uid, _cur_seat, player->_seatid);
		return -1;
	}
	if (do_zi_mo_hu(player) < 0)
	{
		GAME_LOG.error("handler_player_operater_ZI_MO, but zi mo hu error.\n");
		return  -1;
	}
	//计算胡牌牌型
	player->_card_type = calculate_card_type(player);

	calculate_cardtype_score(player->_card_type, player, NULL, NULL);

	calculate_total_winlose_score();

	//鑳＄墝鎴愬姛
	JsonPacket packet;
	packet["cmd"] = SERVER_ZIMOHU;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_ZIMOHU.\n");
	broadcast(NULL, packet);

	//娓告垙缁撶畻
	_hu_flash_timer.start();

	return 0;
}




int Room::handler_player_operater_PUTOUT_MJ(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player->_seatid[%d].\n", uid, player->_seatid);
		return -1;
	}
	if (player->_hole_mjs.mjs.size() % 3 != 2)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player hole mjs not 3n+2.\n", uid);
		return -1;
	}
	int outmj_val = JsonTo<int>(jpacket["out_mj"]);

	do_PUTOUT_MJ(player, outmj_val);

	return 0;
}

int Room::handler_robot_auto_out_mj(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, uid[%d],player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player->_seatid[%d].\n", uid, player->_seatid);
		return -1;
	}
	if (player->_hole_mjs.mjs.size() % 3 != 2)
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, cur_seat[%d], player hole mjs not 3n+2.\n", uid);
		return -1;
	}

	int num = player->_hole_mjs.mjs.size();
	int outmj_val = player->_hole_mjs.mjs[num - 1].val;
	do_PUTOUT_MJ(player, outmj_val);

	return 0;

}



int Room::do_PUTOUT_MJ(Player *player, int outmj_val)
{
	if (!Mj::check_mjval(outmj_val))
	{
		GAME_LOG.error("handler_player_operater_PUTOUT_MJ, outmj_val[%d] error.\n", outmj_val);
		return -1;
	}

	Mj outmj(outmj_val);

	//检查麻将是否在手牌中
	//std::vector<Mj>::iterator it;
	auto itr = std::find(player->_hole_mjs.mjs.begin(), player->_hole_mjs.mjs.end(), outmj);
	if (itr == player->_hole_mjs.mjs.end())
	{
		GAME_LOG.error("do_PUTOUT_MJ, outmj[%d], not in _hole_mjs.\n", outmj.val);
		return -1;
	}

	player->_getin_outmj_timer.stop();
	player->do_out_mj(outmj);

	_cur_outmj_player = player;
	_cur_outmj = outmj;

	//清楚这些用户的回应状态 重复
	// 	std::map<int, Player*>::iterator it;
	// 	int c = 0;
	// 	for (it = _players.begin(); it != _players.end(); it++)
	// 	{
	// 		Player *p = it->second;
	// 		if ( p == player)
	// 		{
	// 			continue;
	// 		}
	// 		P_CHECK pcheck;
	// 		pcheck.clear();
	// 		pcheck.player = p;
	// 		_m_check[c] = pcheck;
	// 		c++;
	// 	}

	//广播打出去的这个牌
	JsonPacket packet;
	packet["cmd"] = SERVER_OUT_ONE_MJ;
	packet["uid"] = player->_uid;
	packet["roomid"] = _roomid;
	packet["seatid"] = player->_seatid;
	packet["out_mj"] = outmj.val;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_OUT_ONE_MJ.\n");
	broadcast(NULL, packet);

	//手牌排序 do_out_mj里面会进行一次排序
	//player->_hole_mjs.sort();

	//改状态
	player->_status = INPLAY_AFTER_PUTOUT_MJ;
	operate_check_after_putout_mj(outmj, player);
	return 0;
}

int Room::handler_player_operater_PENG(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_PENG, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	int m_i = -1;
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._player == player)
		{
			m_i = i;
			break;
		}
	}
	if (m_i == -1)
	{
		GAME_LOG.fatal("handler_player_operater_PENG, submit uid not in _m_check arr.\n");
		return -1;
	}
	if (_m_check[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_PENG, _player_operation not OP_NOT_CHECK\n");
		return -1;
	}

	if (do_peng(player, _cur_outmj_player, _cur_outmj) < 0)
	{
		GAME_LOG.error("cur player[%d] can not peng outmj[%d].\n", player->_uid, _cur_outmj.val);
		return -1;
	}

	_m_check[m_i]._player_operation = OP_PENG;
	player->_pass_timer.stop();

	_cur_seat = player->_seatid;
	//发送碰牌成功
	JsonPacket packet;
	packet["cmd"] = SERVER_PENG;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["mj"] = _cur_outmj.val;
	packet["from_seatid"] = _cur_outmj_player->_seatid;
	packet["expire"] = 15;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_PENG.\n");
	broadcast(NULL, packet);

	_gang_shang_pao_check_flag = 0;


	//责任鸡广播
	if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
	{
		_zherenji_from_player = _cur_outmj_player;
		_zherenji_to_player = player;
		_zherenji_type = 3;
		JsonPacket packet;
		packet["cmd"] = SERVER_ZHE_REN_JI_BC;
		packet["zherenji_from_uid"] = _zherenji_from_player->_uid;
		packet["zherenji_from_seatid"] = _zherenji_from_player->_seatid;
		packet["uid"] = _zherenji_to_player->_uid;
		packet["seatid"] = _zherenji_to_player->_seatid;

		GAME_LOG.debug("SERVER_ZHE_REN_JI_BC.\n");
		broadcast(NULL, packet);
	}

	player->_status = INPLAY_AFTER_PENG_MJ;
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p == player) continue;
		p->_status = INPlAY;
	}

	//碰牌后看能否杠牌，听牌
	operate_check_after_peng_mj(player);

	return 0;
}

int Room::handler_player_operater_FANG_GANG(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}

	player->_pass_timer.stop();

	int m_i = -1;
	for (int i = 0; i<_player_num - 1; i++)
	{
		if (_m_check[i]._player == player)
		{
			m_i = i;
			break;
		}
	}
	if (m_i == -1)
	{
		GAME_LOG.fatal("handler_player_operater_FANG_GANG, submit uid not in _m_check arr.\n");
		return -1;
	}
	if (_m_check[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, _player_operation not OP_NOT_CHECK.\n");
		return -1;
	}
	_m_check[m_i]._player_operation = OP_GANG;

	if (do_fang_gang(player, _cur_outmj_player, _cur_outmj) < 0)
	{
		GAME_LOG.error("handler_player_operater_FANG_GANG, player[%d], out_mj[%d], do_fang_gang error.\n", player->_uid, _cur_outmj.val);
		return -1;
	}

	_cur_seat = player->_seatid;

	//发送放杠成功
	JsonPacket packet;
	packet["cmd"] = SERVER_FANG_GANG;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["mj"] = _cur_outmj.val;
	packet["from_seatid"] = _cur_outmj_player->_seatid;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_FANG_GANG.\n");
	broadcast(NULL, packet);

	_gang_shang_pao_check_flag = FANG_GANG;

	//责任鸡检查
	if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
	{
		_zherenji_from_player = _cur_outmj_player;
		_zherenji_to_player = player;
		_zherenji_type = 4;
		JsonPacket packet;
		packet["cmd"] = SERVER_ZHE_REN_JI_BC;
		packet["zherenji_from_uid"] = _zherenji_from_player->_uid;
		packet["zherenji_from_seatid"] = _zherenji_from_player->_seatid;
		packet["uid"] = _zherenji_to_player->_uid;
		packet["seatid"] = _zherenji_to_player->_seatid;
		GAME_LOG.debug("SERVER_ZHE_REN_JI_BC.\n");
		broadcast(NULL, packet);
	}


	//再摸一张牌	
	getin_mj(player, 1);

	return 0;
}

int Room::handler_player_operater_FANG_PAO_HU(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}

	player->_pass_timer.stop();

	int m_i = -1;
	for (int i = 0; i<_player_num - 1; i++)
	{
		if (_m_check[i]._player == player)
		{
			m_i = i;
			break;
		}
	}
	if (m_i == -1)
	{
		GAME_LOG.fatal("handler_player_operater_FANG_PAO_HU, submit uid not in _m_check arr.\n");
		return -1;
	}
	if (_m_check[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, _player_operation not OP_NOT_CHECK\n");
		return -1;
	}

	_m_check[m_i]._player_operation = OP_HU;

	if (do_fang_pao_hu(player, _cur_outmj, _cur_outmj_player) < 0)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, player[%d], out_mj[%d], do_fang_pao_hu error.\n", player->_uid, _cur_outmj.val);
		return -1;
	}

	//冲锋鸡
	// 	if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
	// 	{
	// 		_chongfengji_player = _cur_outmj_player;
	// 		JsonPacket packet;
	// 		packet["cmd"] = SERVER_CHONG_FENG_JI_BC;
	// 		packet["uid"] = _chongfengji_player->_uid;
	// 		packet["seatid"] = _chongfengji_player->_seatid;
	// 		GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
	// 		
	// 		broadcast(NULL, packet);
	// 	}

	//发送放炮胡成功
	JsonPacket packet;
	packet["cmd"] = SERVER_FANG_PAO_HU;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["mj"] = _cur_outmj.val;
	packet["from_seatid"] = _cur_outmj_player->_seatid;
	form_player_all_mj_info_json(player, packet, "mjs_info");
	GAME_LOG.debug("SERVER_FANG_PAO_HU.\n");
	broadcast(NULL, packet);


	//牌型	
	player->_card_type = calculate_card_type(player);
	calculate_cardtype_score(player->_card_type, NULL, _cur_outmj_player, player);

	if (!if_ypsx())
	{
		calculate_total_winlose_score();
		_cur_seat = player->_seatid;
		_hu_flash_timer.start();
	}
	else //一炮多响
	{
		if (outmj_ypsx_player_all_check())
		{
			GAME_LOG.debug("ypsx, fangpao_hu, a.\n");
			calculate_total_winlose_score();
			_cur_seat = player->_seatid;
			_hu_flash_timer.start();
		}
		else
		{
			GAME_LOG.debug("ypsx, fangpao_hu, b.\n");
			//noting to do 
		}
	}

	return 0;
}

int Room::handler_player_operater_QIANG_GANG_HU(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_FANG_PAO_HU, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}

	int m_i = -1;
	for (int i = 0; i<_player_num - 1; i++)
	{
		if (_m_check_qgh[i]._player == player)
		{
			m_i = i;
			break;
		}
	}
	if (m_i == -1)
	{
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU, player[%d] not in _m_check_qgh arr.\n", uid);
		return -1;
	}
	if (_m_check_qgh[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_QIANG_GANG_HU, player[%d] _player_operation not OP_NOT_CHECK\n", uid);
		return -1;
	}

	int opt = JsonTo<int>(jpacket["opt"]);
	if (opt == 0) //选择不抢杠胡
	{
		GAME_LOG.debug("m_i:%d.\n", m_i);
		_m_check_qgh[m_i]._player_operation = OP_PASS;
		int cnt = 0;
		for (int i = 0; i<_player_num - 1; i++)
		{
			GAME_LOG.debug("_m_check_qgh[%d]._player_operation=%d.\n", i, _m_check_qgh[i]._player_operation);
			if (_m_check_qgh[i]._player_operation == OP_PASS)
			{
				cnt++;
				if (cnt >= _player_num - 1)
				{
					//都不抢杠, 继续明杠
					do_MING_GANG(_cur_qgh_player);
					return 0;
				}
			}
			else if (_m_check_qgh[i]._player_operation == OP_NOT_CHECK) //还有未抢杠胡的继续发送抢杠胡。
			{
				send_bar_operate_check_qiang_gang_hu(_m_check_qgh[i]._player, _cur_qgh_mj);
				return 0;
			}
		}

	}
	else if (opt == 1) //选择抢杠胡
	{
		if (do_qiang_gang_hu(player, _cur_qgh_mj, _cur_qgh_player) < 0)
		{
			GAME_LOG.error("do_qiang_gang_hu error.\n");
			return -1;
		}

		player->_card_type = calculate_card_type(player);
		calculate_cardtype_score(player->_card_type, NULL, _cur_qgh_player, player);
		calculate_total_winlose_score();

		_m_check_qgh[m_i]._player_operation = OP_HU;

		//发送抢杠胡
		JsonPacket packet;
		packet["cmd"] = SERVER_QIANG_GANG_HU;
		packet["uid"] = player->_uid;
		packet["seatid"] = player->_seatid;
		packet["roomid"] = player->_roomid;
		packet["mj"] = _cur_qgh_mj.val;
		form_player_all_mj_info_json(player, packet, "mjs_info");
		GAME_LOG.debug("SERVER_QIANG_GANG_HU.\n");
		broadcast(NULL, packet);

		_hu_flash_timer.start();
	}

	return 0;
}

int Room::do_qiangganghu_timeout_pass(Player *player)
{
	int m_i = -1;
	int m_o = -1;
	for (int i = 0; i<2; i++)
	{
		if (_m_check_qgh[i]._player == player)
		{
			m_i = i;
		}
		else
		{
			m_o = i;
		}
	}
	if (m_i == -1)
	{
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU,m_i -1.\n");
		return -1;
	}
	else if (m_o == -1)
	{
		GAME_LOG.fatal("handler_player_operater_QIANG_GANG_HU, mo -1\n");
		return -1;
	}
	if (_m_check_qgh[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("handler_player_operater_QIANG_GANG_HU, player[%d] _player_operation not OP_NOT_CHECK\n", _m_check_qgh[m_i]._player->_uid);
		return -1;
	}

	GAME_LOG.debug("m_i:%d.\n", m_i);
	_m_check_qgh[m_i]._player_operation = OP_PASS; //timeout 涓嶆姠鏉?
	GAME_LOG.debug("_m_check_qgh[0]._player_operation=%d, _m_check_qgh[1]._player_operation=%d.\n", _m_check_qgh[0]._player_operation, _m_check_qgh[1]._player_operation);


	if (_m_check_qgh[0]._player_operation != OP_NOT_CHECK
		&& _m_check_qgh[1]._player_operation != OP_NOT_CHECK) //涓や釜鐜╁閮芥搷浣滃畬姣曪紝涓旀湁鐜╁鐐逛簡鎶㈡潬鑳?,娓告垙
	{
		if (_m_check_qgh[0]._player_operation == OP_PASS
			&& _m_check_qgh[1]._player_operation == OP_PASS)
		{
			//閮戒笉鎶㈡潬, 缁х画鏄庢潬
			do_MING_GANG(_cur_qgh_player);
		}
		else
		{
			if (do_qiang_gang_hu(_m_check_qgh[m_o]._player, _cur_qgh_mj, _cur_qgh_player) < 0)
			{
				GAME_LOG.error("do_qiang_gang_hu error22.\n");
				return -1;
			}
			//鍙戦€佹姠鏉犺儭
			JsonPacket packet;
			packet["cmd"] = SERVER_QIANG_GANG_HU;
			packet["uid"] = _m_check_qgh[m_o]._player->_uid;
			packet["seatid"] = _m_check_qgh[m_o]._player->_seatid;
			packet["roomid"] = _m_check_qgh[m_o]._player->_roomid;
			form_player_all_mj_info_json(_m_check_qgh[m_o]._player, packet, "mjs_info");
			GAME_LOG.debug("SERVER_QIANG_GANG_HU22.\n");
			broadcast(NULL, packet);

			_next_banker_seat = _cur_qgh_player->_seatid;
			_hu_flash_timer.start();
		}
	}

	return 0;
}



int Room::handler_player_operater_PASS(Player *player, NetworkSessionBase* session)
{
	if (_state != STATE_PLAYING)
	{
		GAME_LOG.error("handler_player_operater_PASS, game_state not STATE_PLAYER.\n");
		return -1;
	}

	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_PASS, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}

	player->_pass_timer.stop();

	do_pass(player);
	return 0;
}

int Room::handler_player_operater_PASS2(Player *player, NetworkSessionBase* session)
{
	if (_state != STATE_PLAYING)
	{
		GAME_LOG.error("handler_player_operater_PASS2, game_state not STATE_PLAYER.\n");
		return -1;
	}

	auto& jpacket = session->_jpacket;
	int uid = JsonTo<int>(jpacket["uid"]);
	if (uid != player->_uid)
	{
		GAME_LOG.error("handler_player_operater_PASS2, uid[%d], player->_uid[%d].\n", uid, player->_uid);
		return -1;
	}
	if (player->_seatid != _cur_seat)
	{
		GAME_LOG.error("handler_player_operater_PASS2, uid[%d],cur_seat[%d], player->_seatid[%d].\n", uid, _cur_seat, player->_seatid);
		return -1;
	}

	if (player->_status != INPLAY_AFTER_GETIN_MJ)
	{
		GAME_LOG.error("handler_player_operater_PASS2, player[%d] status[%d] not INPLAY_AFTER_GETIN_MJ[3].\n", player->_uid, player->_status);
		return -1;
	}

	if (!check_zi_mo_hu(player) 
		&& !check_ang_gang(player, player->_mo_mj) 
		&& !check_ming_gang(player, player->_mo_mj)) 
	{
		return 0;
	}

	//姝ゆ椂鑷姩鍑虹墝
	if (player->_cur_baoting_flag)
	{
		do_PUTOUT_MJ(player, player->_mo_mj.val);
	}
	return 0;
}

int Room::do_pass(Player *player)
{
	int m_i = -1;
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._player == player)
		{
			m_i = i;
			break;
		}
	}

	if (m_i == -1)
	{
		GAME_LOG.fatal("do_pass, player[%d] not in _m_check arr.\n", player->_uid);
		return -1;
	}
	if (_m_check[m_i]._player_operation != OP_NOT_CHECK)
	{
		GAME_LOG.error("do_pass, player[%d] _player_operation not OP_NOT_CHECK.\n", player->_uid);
		return -1;
	}

	if (_m_check[m_i]._fangpao_hu_flag == true) //能胡不胡，本圈过手不能胡
	{
		player->_guo_shou_bu_hu_flag = 1;
	}

	_m_check[m_i]._player_operation = OP_PASS;

	JsonPacket packet;
	packet["cmd"] = SERVER_PASS;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	GAME_LOG.debug("SERVER_PASS.\n");
	
	unicast(player, packet);

	if (!if_ypsx())
	{
		//有人都操作了
		if (outmj_all_check())
		{
			_cur_seat = next_seat(_cur_seat);
			Player *player = _seats[_cur_seat]._player;
			_gang_shang_pao_check_flag = 0;

			//冲锋鸡
			if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
			{
				_chongfengji_player = _cur_outmj_player;
				JsonPacket packet;
				packet["cmd"] = SERVER_CHONG_FENG_JI_BC;
				packet["uid"] = _chongfengji_player->_uid;
				packet["seatid"] = _chongfengji_player->_seatid;
				GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
				
				broadcast(NULL, packet);
			}

			getin_mj(player);
		}
		else
		{
			//所有还未操作的用户 重新计算时间
			for (int i = 0; i < _player_num - 1; i++)
			{
				if (_m_check[i]._player_operation == OP_NOT_CHECK)
				{
					send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);
					_m_check[i]._player->_pass_timer.start();
					return 0;
				}
			}
		}
	}
	else //一炮多响
	{
		//所有人都选择了pass
		if (outmj_all_pass())
		{
			GAME_LOG.debug("ypsx, pass, a.\n");
			_cur_seat = next_seat(_cur_seat);
			Player *player = _seats[_cur_seat]._player;
			_gang_shang_pao_check_flag = 0;

			//冲锋鸡
			if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
			{
				_chongfengji_player = _cur_outmj_player;
				JsonPacket packet;
				packet["cmd"] = SERVER_CHONG_FENG_JI_BC;
				packet["uid"] = _chongfengji_player->_uid;
				packet["seatid"] = _chongfengji_player->_seatid;

				GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
				
				broadcast(NULL, packet);
			}


			getin_mj(player);
		}
		//判断所有可胡牌的人都对操作盘做出了pass的应答
		else if (outmj_hu_player_all_pass())
		{
			GAME_LOG.debug("ypsx, pass, b.\n");
			for (int i = 0; i < _player_num - 1; i++)
			{
				//所有还未操作的用户 重新计算时间
				if (_m_check[i]._player_operation == OP_NOT_CHECK
					&& _m_check[i]._fangpao_hu_flag == false
					&& _m_check[i]._peng_flag == true) //两个人能胡，都pass, 另外一个能碰	
				{
					send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);
					_m_check[i]._player->_pass_timer.start();
					return 0;
				}
			}
		}
		else if (outmj_ypsx_player_all_check() && outmj_ypsx_player_check_has_hu())
		{
			GAME_LOG.debug("ypsx, pass, c.\n");
			GAME_LOG.debug("ypsx, one player pass, has player do hu. all do.\n");
			calculate_total_winlose_score();
			_hu_flash_timer.start();
		}
		else
		{
			GAME_LOG.debug("ypsx, pass, d.\n");
			//do noting
		}
	}
	return 0;
}

int Room::handler_player_dissolution_room_req(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;

	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		GAME_LOG.debug("only kaifang room can diss room.\n");
		return 0;
	}
	//娓呯悊鍒濆鍊?
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p == player)
		{
			p->_agree_dissroom = 1;//鍙戣捣鑰?
		}
		else
		{
			p->_agree_dissroom = 0; //鏈洖澶?
		}
	}

	if ((int)(_players.size()) < _player_num
		&& _state == STATE_READY
		&& _rest_board == _board_choose)
	{
		_isdissolution << jpacket["dissolution"];
		do_dissolution_room();
	}
	else
	{
		JsonPacket packet;
		packet["cmd"] = SERVER_DISSOLUTION_ROOM_REQ_BC;
		packet["init_uid"] = player->_uid;
		packet["init_nick_name"] = player->_nick_name;
		packet["roomid"] = _roomid;
		packet["expire"] = 100;
		GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_REQ_BC.\n");
		
		broadcast(NULL, packet);
		//解散房间投票计时器
		RunOnce(_dissolution_confirm_timer, 100, [this]() {
			GAME_LOG.debug("dissolution_confirm_timer_out.\n");
			//_dissolution_confirm_timer.stop();
			do_dissolution_room();
		});
	}
	return 0;
}

int Room::handler_player_dissolution_room_confirm(Player *player, NetworkSessionBase* session)
{
	auto& jpacket = session->_jpacket;
	int confirm = JsonTo<int>(jpacket["confirm"]);

	if (player->_agree_dissroom == 1)
	{
		GAME_LOG.error("dissolution_room_req player can not confirm.\n");
		return -1;
	}
	JsonPacket packet;
	packet["cmd"] = SERVER_DISSOLUTION_ROOM_CONFIRM_BC;
	packet["uid"] = player->_uid;
	packet["nick_name"] = player->_nick_name;
	packet["roomid"] = _roomid;
	packet["confirm"] = confirm;
	GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_CONFIRM_BC.\n");
	
	broadcast(NULL, packet);

	if (confirm == 0)
	{
		JsonPacket packet;
		packet["cmd"] = SERVER_DISSOLUTION_ROOM_RESULT_BC;
		packet["roomid"] = _roomid;
		packet["result"] = 0;
		GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_RESULT_BC.\n");
		
		broadcast(NULL, packet);
		player->_agree_dissroom = 3;
		_dissolution_confirm_timer.stop();
	}
	else if (confirm == 1)
	{
		player->_agree_dissroom = 2;
		//鍚屾剰
		if ((_player_num == 2 && confirm_cnt() >= 1)
			|| (_player_num == 3 && confirm_cnt() >= 2)
			|| (_player_num == 4 && confirm_cnt() >= 2))
		{
			//澶勭悊瑙ｆ暎鎴块棿
			do_dissolution_room();
		}
	}
	return 0;
}

int Room::confirm_cnt()
{
	int cnt = 0;
	std::map<int, Player *>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p->_agree_dissroom == 2)
		{
			cnt++;
		}
	}
	return cnt;
}

int Room::if_dissolution()
{
	std::map<int, Player *>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p->_agree_dissroom == 1)
		{
			return 1;
		}
	}
	return 0;
}

int Room::do_dissolution_room()
{
	if (_state == STATE_READY && _rest_board == _board_choose)
	{
		game_sql::update_room_ticket_status(_rec_id, 1);
	}
	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		GAME_LOG.error("only kaifang room can do_dissolution_room room.\n");
		return -1;
	}

	_dissolution_confirm_timer.stop();

	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		p->_agree_dissroom = 0;
	}

	if ((int)(_players.size()) >= _player_num)
	{
		send_all_end_info();
	}

	JsonPacket packet;
	packet["cmd"] = SERVER_DISSOLUTION_ROOM_RESULT_BC;
	packet["roomid"] = _roomid;
	packet["result"] = 1;
	if (YXJMJ_SERVER._game_flag < 1000000 //是开房
		&& _state == STATE_READY //准备状态
		&& _isdissolution == 1)//所有人都同意了
	{
		packet["uid"] = _seats[0]._player->_uid;
		packet["ticket_id"] = _rec_id;
	}
	GAME_LOG.debug("SERVER_DISSOLUTION_ROOM_RESULT_BC1.\n");
	
	broadcast(NULL, packet);
	//杀所有用户 删房间实例
	del_all_players();
	YXJMJ_SERVER._rooms.DestoryRoom(_roomid);
	return 0;
}

int Room::handler_player_ready(Player *player, NetworkSessionBase* session)
{
	//auto& jpacket = session->_jpacket;
	if (_state != STATE_READY)
	{
		GAME_LOG.error("handler_player_ready, player[%d], state[%d] error.", player->_uid, _state);
		return -1;
	}
	if (player->_status == READY)
	{
		GAME_LOG.error("handler_player_ready, player[%d], status[%d] error.", player->_uid, player->_status);
		return -1;
	}

	player->_status = READY;

	if (_has_timer)
	{
		player->_ready_timer.stop();
	}
	JsonPacket packet;
	packet["cmd"] = SERVER_READY_BC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	GAME_LOG.debug("SERVER_READY_BC.\n");
	
	broadcast(NULL, packet);
	if (0 == judge_game_start())
	{
		start_game();
	}

	return 0;
}


bool Room::if_ypsx()
{
	int cnt = 0;
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag == true) cnt++;
	}
	if (cnt > 1)
	{
		return true;
	}
	return false;
}


bool Room::outmj_all_check()
{
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._player_operation == OP_NOT_CHECK)
		{
			return false;
		}
	}
	return true;
}

bool Room::outmj_ypsx_player_all_check()
{
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag == true && _m_check[i]._player_operation == OP_NOT_CHECK)
		{
			return false;
		}
	}
	return true;
}

bool Room::outmj_ypsx_player_check_has_hu()
{

	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag == true && _m_check[i]._player_operation == OP_HU)
		{
			return true;
		}
	}
	return false;
}


bool Room::outmj_all_pass()
{
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._player_operation != OP_PASS)
		{
			return false;
		}
	}
	return true;
}

bool Room::outmj_hu_player_all_pass()
{
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag == true && _m_check[i]._player_operation != OP_PASS)
		{
			return false;
		}
	}
	return true;
}



Json::Value Room::calculate_quickly_match()
{
	Json::Value packet;
	int max_score(-1000);
	set<int> max_people;
	vector<int> hu_people;
	//取出分数最大的几个人
	for (auto info : _players)
	{
		auto player = info.second;
		if (player->_score > max_score)
		{
			max_people.clear();
			max_score = player->_score;
			max_people.insert(player->_uid);
		}
		else if (player->_score == max_score)
		{
			max_people.insert(player->_uid);
		}
	}
	max_score = -1;
	//取出胡牌数量最多的几个人
	for (auto playerid : max_people)
	{
		auto player = _players[playerid];
		if (player->_score > max_score)
		{
			hu_people.clear();
			max_score = player->_quick_hu_count;
			hu_people.push_back(player->_uid);
		}
		else if (player->_quick_hu_count == max_score)
		{
			hu_people.push_back(player->_uid);
		}
	}
	int winner;
	int word(-1);
	const static int match_pai[27] = {
		S1,W1,T1,
		S2,W2,T2,
		S3,W3,T3,
		S4,W4,T4,
		S5,W5,T5,
		S6,W6,T6,
		S7,W7,T7,
		S8,W8,T8,
		S9,W9,T9 };
	//如果人数大于1 随机一个用户胜利
	if (hu_people.size() > 1)
	{
		srand(time(NULL) + _match_id);
		int rand_count = rand();
		winner = hu_people[rand_count % hu_people.size()];
		word = (rand_count % 10) + 17;//赢家至少摇出17以上
	}
	else
	{
		winner = hu_people[0];
	}
	packet["cmd"] = SERVER_QUICK_MATCH_RESULT_BC;
	packet["winner"] = winner;
	packet["type"] = game_sql::get_shop_match_board_type(_match_id);
	string losters;
	for (auto info : _players)
	{
		losters.append(to_string(info.second->_uid));
		losters.append("|");
	}
	int game_rec_id = game_sql::add_quick_match_record(_match_id, winner, losters);
	for (auto info : _players)
	{
		auto player = info.second;
		Json::Value val;
		val["uid"] = player->_uid;
		val["score"] = player->_score;
		val["hu_count"] = player->_quick_hu_count;
		val["seatid"] = player->_seatid;
		if (word != -1)
		{
			if (player->_uid == winner)
			{
				val["rand_pai"] = match_pai[word];
			}
			else
			{
				auto itr = find(hu_people.begin(), hu_people.end(), player->_uid);
				if (itr != hu_people.end())
				{
					srand(time(NULL) + _match_id);
					int rand_count = rand();
					val["rand_pai"] = match_pai[rand_count % word];
				}
			}
		}
		packet["result_list"].append(val);
		//机器人不发码，还回去
		if (player->_robot_flag != 0)
		{
			continue;
		}
		if (player->_uid == winner)
		{
			auto id = _match_reward.front();
			game_sql::change_discount_status(player->_uid, id, game_rec_id);
			_match_reward.pop_front();
		}
		else
		{
			auto id = _match_reward.back();
			game_sql::change_discount_status(player->_uid, id, game_rec_id);
			_match_reward.pop_back();
		}
	}
	game_sql::return_discount_codes(_match_reward);
	GAME_LOG.debug("SERVER_QUICK_MATCH_RESULT_BC.\n");
	//
	//broadcast(NULL, packet);
	_match_id = 0;
	_match_reward.clear();
	//_quickly_shop_timer.start();
	// 	RunOnce(60, [this]() {
	// 		GAME_LOG.debug("din_que_timer_cb.\n");
	// 		state = STATE_READY;
	// 		del_all_players();
	// 	});
	return packet;
}

int Room::cardtype_to_base_score(int card_type)
{
	/*
	enum CARD_TYPE {
	CARD_TYPE_ERROR = 0,     //无牌型
	CARD_TYPE_PINGHU =  1,   //平胡，1
	CARD_TYPE_DADUIZI = 2,   //大对子 (碰碰胡)，5
	CARD_TYPE_QIDUI   = 3,   //七对   (七小对)，10
	CARD_TYPE_QINGYISE = 4,  //清一色 ，10
	CARD_TYPE_DANDIAO = 5,   //单调，10
	CARD_TYPE_DI_TING = 6, //地听，10
	CARD_TYPE_QINGDADUI = 7, //清大对 (清一色碰碰胡)，15
	CARD_TYPE_DANDIAOQINGYISE = 8, //单调清一色，20
	CARD_TYPE_TIAN_TING = 9,//天听，20
	CARD_TYPE_LONGQIDUI = 10, //龙七对 (豪华七对)，20
	CARD_TYPE_QINGQIDUI = 11, //清七对 (清一色七小对)，20
	CARD_TYPE_TIANHU = 12, //天胡，20
	CARD_TYPE_DIHU = 13, //地胡，20
	CARD_TYPE_SHA_BAO = 14, //杀报
	CARD_TYPE_QINGLONGBEI = 15, //清龙背 (清一色 豪华七对)，30
	};
	*/
	// 	static map<int, int> card_type_score =
	// 	{
	// 		{ CARD_TYPE_PINGHU,1 },
	// 		{ CARD_TYPE_DADUIZI,5 },
	// 		{ CARD_TYPE_QIDUI,10 },
	// 		{ CARD_TYPE_LONGQIDUI,20 },
	// 		{ CARD_TYPE_QINGYISE,10 },
	// 		{ CARD_TYPE_QINGDADUI,15 },
	// 		{ CARD_TYPE_QINGQIDUI,20 },
	// 		{ CARD_TYPE_QINGLONGBEI,30 },
	// 		{ CARD_TYPE_DANDIAO,10 },
	// 		{ CARD_TYPE_DANDIAOQINGYISE,20 },
	// 		{ CARD_TYPE_TIANHU,20 },
	// 		{ CARD_TYPE_DIHU,20 },
	// 		{ CARD_TYPE_TIAN_TING,20 },
	// 		{ CARD_TYPE_DI_TING,10 }
	// 	};

	int base_score = 0;
	if (card_type == CARD_TYPE_ERROR)
	{
		GAME_LOG.fatal("card_type_ERROR.\n");
	}
	else if (card_type == CARD_TYPE_PINGHU) { //平胡 1倍
		base_score = 1;
	}
	else if (card_type == CARD_TYPE_DADUIZI) { //大对子 5倍
		base_score = 5;
	}
	else if (card_type == CARD_TYPE_QIDUI) {//七对 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_LONGQIDUI) {//龙七对 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_QINGYISE) {//清一色 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_QINGDADUI) {//清大对 15倍
		base_score = 15;
	}
	else if (card_type == CARD_TYPE_QINGQIDUI) {//清七对 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_QINGLONGBEI) {//清龙背 30倍
		base_score = 30;
	}
	else if (card_type == CARD_TYPE_DANDIAO) {//单吊 10倍
		base_score = 10;
	}
	else if (card_type == CARD_TYPE_DANDIAOQINGYISE) {//单调清一色 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_TIANHU) { //天胡 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_DIHU) { //地胡 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_TIAN_TING) {//天听 20倍
		base_score = 20;
	}
	else if (card_type == CARD_TYPE_DI_TING) { //地听 10 倍
		base_score = 10;
	}

	return base_score;
}

void Room::calculate_cardtype_score(int card_type, Player *mo_player, Player *fangpao_player, Player* jiepao_player)
{

	int base_score = cardtype_to_base_score(card_type);

	if (_end_type == ET_ZI_MO) //自摸
	{
		std::map<int, Player*>::iterator it;
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			if (p == mo_player) continue;
			else
			{
				if (p->_cur_baoting_flag == 1)//出现杀报 1是天听标识
				{
					p->_card_type = CARD_TYPE_SHA_BAO;
					if (p->_seatid == _banker_seat) //杀天听
					{
						int add_score = 0;
						if (base_score < 20) add_score = 20;
						else add_score = base_score;

						p->_cardtype_score += -(add_score + 1);
						mo_player->_cardtype_score += (add_score + 1);
					}
					else if (p->_seatid != _banker_seat) //杀地听
					{
						int add_score = 0;
						if (base_score < 10) add_score = 10;
						else add_score = base_score;

						p->_cardtype_score += -(add_score + 1);
						mo_player->_cardtype_score += (add_score + 1);
					}
				}
				else //正常模式
				{
					p->_cardtype_score = -(1 + base_score);
					mo_player->_cardtype_score += (1 + base_score);
				}
			}
		}
	}
	else if (_end_type == ET_GANG_KAI_ZI_MO) //杠开
	{
		std::map<int, Player*>::iterator it;
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			if (p == mo_player) continue;
			else
			{
				if (p->_cur_baoting_flag == 1)//出现杀报
				{
					p->_card_type = CARD_TYPE_SHA_BAO;
					if (p->_seatid == _banker_seat) //杀天听
					{
						int add_score = 0;
						if (base_score < 20) add_score = 20;
						else add_score = base_score;

						p->_cardtype_score += -(add_score + 2);
						mo_player->_cardtype_score += (add_score + 2);
					}
					else if (p->_seatid != _banker_seat) //杀地听
					{
						int add_score = 0;
						if (base_score < 10) add_score = 10;
						else add_score = base_score;

						p->_cardtype_score += -(add_score + 2);
						mo_player->_cardtype_score += (add_score + 2);
					}
				}
				else //正常模式
				{
					p->_cardtype_score = -(2 + base_score);
					mo_player->_cardtype_score += (2 + base_score);
				}
			}

		}
	}
	else if (_end_type == ET_FANG_PAO) //放炮
	{
		if (fangpao_player->_cur_baoting_flag == 1)//出现杀报
		{
			fangpao_player->_card_type = CARD_TYPE_SHA_BAO;
			if (fangpao_player->_seatid == _banker_seat)
			{
				if (base_score < 20) base_score = 20;
				fangpao_player->_cardtype_score += -base_score;
				jiepao_player->_cardtype_score += base_score;
			}
			else if (fangpao_player->_seatid != _banker_seat)
			{
				if (base_score < 10) base_score = 10;
				fangpao_player->_cardtype_score += -base_score;
				jiepao_player->_cardtype_score += base_score;
			}
		}
		else//正常模式
		{
			fangpao_player->_cardtype_score += -base_score;
			jiepao_player->_cardtype_score += base_score;
		}
	}
	else if (_end_type == ET_FANG_RE_PAO) //放热炮
	{
		fangpao_player->_cardtype_score += -(base_score + 2);
		jiepao_player->_cardtype_score += (base_score + 2);
	}
	else if (_end_type == ET_QIANG_GANG) //抢杠胡
	{
		fangpao_player->_cardtype_score += -(base_score + 1);
		jiepao_player->_cardtype_score += (base_score + 1);
	}

}


void Room::do_fangpaiji()//番牌鸡
{
	if (!_comm_mjs.pop_mj(_fangpaiji_mj))
	{
		GAME_LOG.debug("do_fangpaiji, no more mjs.\n");
		//没有牌了，所以鸡牌都不算
		std::map<int, Player*>::iterator it;
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			p->_fangpaiji_num = 0;
		}
	}
	else
	{

		std::map<int, Player*>::iterator it;
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			if ((_end_type == ET_FANG_RE_PAO && _cur_outmj_player == p)
				|| (_end_type == ET_QIANG_GANG && _cur_qgh_player == p))//放热炮者不计算翻牌鸡
			{
				GAME_LOG.debug("----------re pao, qiang gang , not calculate fangpaiji-------------p->_uid[%d].\n", p->_uid);
				p->_fangpaiji_num = 0;
			}
			else
			{
				p->_fangpaiji_num = p->calculate_fangpaiji_base_num(_fangpaiji_mj);
			}
		}
	}
	//当一个人每有一个鸡分 所有人都要给这个人一分
	std::map<int, Player*>::iterator it1;
	for (it1 = _players.begin(); it1 != _players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2 = _players.begin(); it2 != _players.end(); it2++)
		{
			Player *p2 = it2->second;
			if (p2 == p)
			{
				p->_fangpaiji_score += p2->_fangpaiji_num * (_player_num - 1);
			}
			else
			{
				p->_fangpaiji_score -= p2->_fangpaiji_num;
			}
		}
	}
}

void Room::do_gudingji() //固定鸡
{
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if ((_end_type == ET_FANG_RE_PAO && _cur_outmj_player == p && _cur_outmj_player->_jiaopai_flag == 1)
			|| (_end_type == ET_QIANG_GANG && _cur_qgh_player == p && _cur_outmj_player->_jiaopai_flag == 1))//放热炮者不计算固定鸡且叫牌玩家
		{
			GAME_LOG.debug("----------re pao, qiang gang , not calculate gudingji-------------p->_uid[%d].\n", p->_uid);
			p->_gudingji_num_hole = 0;
			p->_gudingji_num_out = 0;
		}
		else if ((_end_type == ET_FANG_RE_PAO && _cur_outmj_player == p && _cur_outmj_player->_jiaopai_flag == 0)
			|| (_end_type == ET_QIANG_GANG && _cur_qgh_player == p && _cur_outmj_player->_jiaopai_flag == 0))//放热炮者不计算固定鸡且叫牌玩家
		{
			p->_gudingji_num_hole = 0;
			p->_gudingji_num_out = p->calculate_gudingji_base_num_out();
		}
		else
		{
			p->_gudingji_num_hole = p->calculate_gudingji_base_num_hole();
			p->_gudingji_num_out = p->calculate_gudingji_base_num_out();
		}
	}

	std::map<int, Player*>::iterator it1;
	for (it1 = _players.begin(); it1 != _players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2 = _players.begin(); it2 != _players.end(); it2++)
		{
			Player *p2 = it2->second;
			if (p == p2)
			{
				continue;
			}
			else
			{

				p->_gudingji_score += p->_gudingji_num_hole;
				p2->_gudingji_score -= p->_gudingji_num_hole;

				if (p->_gudingji_num_out >= 0)
				{
					p->_gudingji_score += p->_gudingji_num_out;
					p2->_gudingji_score -= p->_gudingji_num_out;
				}
				else if (p->_gudingji_num_out < 0 && p2->_jiaopai_flag == 1)
				{

					p->_gudingji_score += p->_gudingji_num_out;
					p2->_gudingji_score -= p->_gudingji_num_out;
				}
			}
		}
	}
}

void Room::do_chongfengji()
{
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if ((_end_type == ET_FANG_RE_PAO && _cur_outmj_player == p && _cur_outmj_player->_jiaopai_flag == 1)
			|| (_end_type == ET_QIANG_GANG && _cur_qgh_player == p && _cur_outmj_player->_jiaopai_flag == 1))//放热炮者不计算冲锋鸡
		{
			GAME_LOG.debug("----------re pao, qiang gang , jiaopai, not calculate chongfengji-------------p->_uid[%d].\n", p->_uid);
			p->_chongfengji_num = 0;
		}
		else
		{
			p->_chongfengji_num = p->calculate_chongfengji_base();
		}
	}

	std::map<int, Player*>::iterator it1;
	for (it1 = _players.begin(); it1 != _players.end(); it1++)
	{
		Player *p = it1->second;
		std::map<int, Player*>::iterator it2;
		for (it2 = _players.begin(); it2 != _players.end(); it2++)
		{
			Player *p2 = it2->second;
			if (p == p2)
			{
				continue;
			}
			else
			{
				if (p->_chongfengji_num > 0)
				{
					p->_chongfengji_score += p->_chongfengji_num * 2;
					p2->_chongfengji_score -= p->_chongfengji_num * 2;
				}
				else if (p->_chongfengji_num < 0 && p2->_jiaopai_flag == 1)
				{
					p->_chongfengji_score += p->_chongfengji_num * 2;
					p2->_chongfengji_score -= p->_chongfengji_num * 2;
				}
			}
		}
	}
}

void Room::do_zherenji()
{
	if (_zherenji_from_player != NULL && _zherenji_to_player != NULL)
	{
		GAME_LOG.debug(" has zherenji.\n ");
		if (_zherenji_to_player->_jiaopai_flag == 1)
		{
			std::map<int, Player*>::iterator it;
			for (it = _players.begin(); it != _players.end(); it++)
			{
				Player *p = it->second;
				if (p == _zherenji_to_player)
				{
					_zherenji_to_player->_zherenji_score += ((_player_num - 1)*_zherenji_type + 1);
				}
				else
				{
					p->_zherenji_score -= _zherenji_type;
					if (p == _zherenji_from_player)
					{
						p->_zherenji_score -= 1;
					}
				}
			}
		}
		else if (_zherenji_to_player->_jiaopai_flag == 0)
		{
			std::map<int, Player*>::iterator it;
			for (it = _players.begin(); it != _players.end(); it++)
			{
				Player *p = it->second;
				if (p == _zherenji_to_player)
				{
					continue;
				}
				else
				{
					if (p->_jiaopai_flag == 1)
					{
						p->_zherenji_score += _zherenji_type;
						_zherenji_to_player->_zherenji_score -= _zherenji_type;

						if (p == _zherenji_from_player)
						{
							p->_zherenji_score += 1;
							_zherenji_to_player->_zherenji_score -= 1;
						}
					}
				}
			}
		}
	}
}


void Room::calculate_total_winlose_score()
{
	do_gang_score(); //计算杠分
	do_fangpaiji();//番牌鸡
	do_gudingji(); //计算固定鸡
	do_chongfengji(); //计算冲锋鸡
	do_zherenji(); //计算责任鸡

	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		p->_winlose_score = p->_cardtype_score + p->_gudingji_score + p->_fangpaiji_score + p->_chongfengji_score + p->_zherenji_score + p->_cur_gang_score;
		p->_score += p->_winlose_score;
	}
}

void Room::do_gang_score()
{
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *player = it->second;
		if (player->_jiaopai_flag == 1)
		{
			for (unsigned int i = 0; i< player->_form_mjs.form_mjz.size(); i++)
			{

				if (_end_type == ET_FANG_RE_PAO && _cur_outmj_player == player && i == (player->_form_mjs.form_mjz.size() - 1))
				{
					//如果出现了热炮的情况 (杠上炮), 放炮玩家的最后那个杠不算
					continue;
				}
				//放杠 谁放的杠谁给3分
				if (player->_form_mjs.form_mjz[i].zu_type == FANG_GANG)
				{
					player->_cur_gang_score += 3;
					player->_cur_fanggang_score += 3;
					int from_seat = player->_form_mjs.form_mjz[i].from_seat;
					_seats[from_seat]._player->_cur_gang_score -= 3;
					_seats[from_seat]._player->_cur_fanggang_score -= 3;

				}
				//明杠 所有其他人给3分
				else if (player->_form_mjs.form_mjz[i].zu_type == MING_GANG)
				{
					player->_cur_gang_score += (_player_num - 1) * 3;
					player->_cur_minggang_score += (_player_num - 1) * 3;
					for (int i = 0; i < _player_num; i++)
					{
						if (_seats[i]._player != player)
						{
							_seats[i]._player->_cur_gang_score -= 3;
							_seats[i]._player->_cur_minggang_score -= 3;
						}
					}
				}
				//暗杠 所有其它人给3分
				else if (player->_form_mjs.form_mjz[i].zu_type == ANG_GANG)
				{
					player->_cur_gang_score += (_player_num - 1) * 3;
					player->_cur_angang_score += (_player_num - 1) * 3;
					for (int i = 0; i < _player_num; i++)
					{
						if (_seats[i]._player != player)
						{
							_seats[i]._player->_cur_gang_score -= 3;
							_seats[i]._player->_cur_angang_score -= 3;
						}
					}
				}
			}
		}
	}
}

void Room::do_huangzhuang()
{

	_end_type = ET_HUANG_ZHUANG;
	/*
	a.查牌后，（各玩家均未叫牌），则各家无输赢，庄家连庄。
	b.查牌后，四家都叫牌，则各家无输赢，庄家连庄。
	c.查牌后，有人叫牌，有人不叫牌。叫牌者根据所叫牌算分，不叫牌者需要分别给每个叫牌者相应的分数。在叫牌者中，有庄家则连庄。没庄家则离庄家最近的下家接庄。
	d.特殊情况，3家叫牌，一家未叫。未叫者付3家，且未叫者接庄。
	*/

	//计算叫牌
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		check_jiaopai_flag(p);
	}

	int cnt = 0;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p->_jiaopai_flag == 1)
		{
			cnt++;
		}
	}

	if (cnt == 0) //a.查牌后，（各玩家均未叫牌），则各家无输赢，庄家连庄。
	{
		_next_banker_seat = _banker_seat;
	}
	else if (cnt == _player_num) //b.查牌后，四家都叫牌，则各家无输赢，庄家连庄。
	{
		_next_banker_seat = _banker_seat;
	}
	else if (cnt == _player_num - 1 && _player_num > 2) // d.特殊情况，其他家都叫牌，一家未叫。未叫者付3家，且未叫者接庄。
	{
		//确认下一局庄家
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			if (p->_jiaopai_flag == 0)
			{
				_next_banker_seat = p->_seatid;
			}
		}

		//未叫牌向叫牌玩家付钱
		//logic
		std::map<int, Player*>::iterator it1;
		for (it1 = _players.begin(); it1 != _players.end(); it1++) //未叫牌者循环
		{
			Player *p1 = it1->second;
			if (p1->_jiaopai_flag == 1) continue;
			//排除去叫牌的下面都是没叫牌的

			std::map<int, Player*>::iterator it2;
			for (it2 = _players.begin(); it2 != _players.end(); it2++) //叫牌者循环
			{
				Player *p2 = it2->second;
				if (p2->_jiaopai_flag == 0) continue;
				//排除去没叫牌的下面都是叫牌的
				//计算叫牌玩家牌型
				p2->_card_type = calculate_jiaopai_card_type(p2);

				int temp_score = cardtype_to_base_score(p2->_card_type);

				p2->_cardtype_score += temp_score;
				p1->_cardtype_score -= temp_score;

			}
		}
	}
	else //c.查牌后，有人叫牌，有人不叫牌。叫牌者根据所叫牌算分，不叫牌者需要分别给每个叫牌者相应的分数。在叫牌者中，有庄家则连庄。没庄家则离庄家最近的下家接庄。
	{
		//确认下一局庄家
		_next_banker_seat = -1;
		for (it = _players.begin(); it != _players.end(); it++)
		{
			Player *p = it->second;
			if (p->_jiaopai_flag == 1 && p->_seatid == _banker_seat)
			{
				_next_banker_seat = p->_seatid;
			}
		}
		if (_next_banker_seat == -1)
		{
			Player *jp_player = NULL;
			jp_player = next_jiaopai_player(_seats[_banker_seat]._player);
			if (jp_player == NULL)
			{
				_next_banker_seat = next_player(_seats[_banker_seat]._player)->_seatid;
			}
			else
			{
				_next_banker_seat = jp_player->_seatid;
			}
		}

		//未叫牌向叫牌玩家付钱
		//logic
		std::map<int, Player*>::iterator it1;
		for (it1 = _players.begin(); it1 != _players.end(); it1++) //未叫牌者循环
		{
			Player *p1 = it1->second;
			if (p1->_jiaopai_flag == 1) continue;
			//排除去叫牌的下面都是没叫牌的

			std::map<int, Player*>::iterator it2;
			for (it2 = _players.begin(); it2 != _players.end(); it2++) //叫牌者循环
			{
				Player *p2 = it2->second;
				if (p2->_jiaopai_flag == 0) continue;
				//排除去没叫牌的下面都是叫牌的
				//计算叫牌玩家牌型
				p2->_card_type = calculate_jiaopai_card_type(p2);

				int temp_score = cardtype_to_base_score(p2->_card_type);

				p2->_cardtype_score += temp_score;
				p1->_cardtype_score -= temp_score;

			}
		}

	}

	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		p->_winlose_score = p->_cardtype_score;
		p->_score += p->_winlose_score;
	}

}

int Room::game_end(int type)
{
	_state = STATE_END;
	GAME_LOG.info("------------now game end----------------.\n");

	JsonPacket packet;
	packet["cmd"] = SERVER_GAME_END_BC;
	packet["roomid"] = _roomid;
	packet["board_choose"] = _board_choose;
	packet["player_num"] = _player_num;
	packet["cur_board"] = _board_choose - _rest_board;
	std::string time_str = general_time_str();
	packet["time_str"] = time_str.c_str();
	packet["end_type"] = _end_type;
	packet["fangpaiji_mj"] = _fangpaiji_mj.val;
	if (_fangpaiji_mj.val != 0)
	{
		packet["fangpaiji_mj_next"] = _fangpaiji_mj.next_fangpai_mj().val;
	}
	else
	{
		packet["fangpaiji_mj_next"] = 0;
	}


	packet["game_flag"] = YXJMJ_SERVER._game_flag;
	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		packet["base_gold"] = _base_gold;
	}

	std::map<int, Player*>::iterator it;
	int i = 0;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		packet["players"][i]["uid"] = p->_uid;
		packet["players"][i]["nick_name"] = p->_nick_name;
		packet["players"][i]["avater_url"] = p->_avater_url;
		packet["players"][i]["seatid"] = p->_seatid;
		packet["players"][i]["jiaopai_flag"] = p->_jiaopai_flag;
		packet["players"][i]["cur_gang_score"] = p->_cur_gang_score;
		packet["players"][i]["cur_angang_score"] = p->_cur_angang_score;
		packet["players"][i]["cur_minggang_score"] = p->_cur_minggang_score;
		packet["players"][i]["cur_fanggang_score"] = p->_cur_fanggang_score;
		packet["players"][i]["cur_fangpaiji_score"] = p->_fangpaiji_score;
		packet["players"][i]["cur_gudingji_score"] = p->_gudingji_score;
		packet["players"][i]["cur_chongfengji_score"] = p->_chongfengji_score;
		packet["players"][i]["cur_zherengji_score"] = p->_zherenji_score;
		packet["players"][i]["cur_cardtype_score"] = p->_cardtype_score;
		//GAME_LOG.debug("uid:%d, base_gold:%d, winlose_score:%d.\n",p->_uid, base_gold, p->_winlose_score);
		//每日任务完成
		auto task_finish = [&](int uid, string task_id)
		{
			std::string key;
			std::stringstream strtime;
			auto currenttime = time(NULL);
			char tAll[255];
			strftime(tAll, sizeof(tAll), "%Y-%m-%d", localtime(&currenttime));
			strtime << tAll;
			key = "task_unclaimed_" + task_id + "_" + strtime.str();
			if (0 != Singleton<RedisClient>::Instance()->command("hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1))
			{
				GAME_LOG.error("redis command fail: hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1);
			}
			else
			{
				GAME_LOG.debug("redis command succ: hincrby %s %s %d", key.c_str(), std::to_string(uid).c_str(), 1);
			}
		};
		if (YXJMJ_SERVER._game_flag > 1000000)
		{
			//打出一个冲锋鸡任务
			if (p->_chongfengji_num > 0)
			{
				task_finish(p->_uid, "4");
			}
			//排位单局获得30分的每日任务
			if (YXJMJ_SERVER._game_flag == 2000001 && p->_winlose_score > 30)
			{
				task_finish(p->_uid, "3");
			}
			int num = p->_winlose_score;
			if (p->_robot_flag == 0 && YXJMJ_SERVER._game_flag / 1000000 == 1)
			{
				int end_winlose_gold = ((p->_gold + num * _base_gold > 0) ? num * _base_gold : p->_gold);
				game_sql::decrease_gold(p->_uid, end_winlose_gold);
				game_sql::insert_gold_change_rec(p->_uid, end_winlose_gold, "金币场", "金币场结算输赢");
				p->_gold += end_winlose_gold;
			}
			//排位分只加不减
			else if (YXJMJ_SERVER._game_flag == 2000001)
			{
				if (p->_winlose_score > 0)
				{
					game_sql::increase_user_result(p->_uid, 1);
					GAME_LOG.debug("uid:%d, add_paiwei_score:%d.\n", p->_uid, p->_winlose_score);
					game_sql::decrease_paiwei_score(p->_uid, p->_winlose_score);
					game_sql::insert_paiwei_score_change_rec(p->_uid, p->_paiwei_score, p->_winlose_score, p->_paiwei_score + p->_winlose_score);
					p->_paiwei_score += p->_winlose_score;
					packet["players"][i]["cur_add_paiwei_score"] = p->_winlose_score;
				}
				else if (p->_winlose_score < 0)
				{
					game_sql::increase_user_result(p->_uid, 2);
					packet["players"][i]["cur_add_paiwei_score"] = 0;
				}
				else
				{
					game_sql::increase_user_result(p->_uid, 3);
					packet["players"][i]["cur_add_paiwei_score"] = 0;
				}
			}
			packet["players"][i]["cur_winlose_score"] = num * _base_gold;
			p->_vec_score.push_back(num* _base_gold);
		}
		else
		{
			packet["players"][i]["cur_winlose_score"] = p->_winlose_score;
			p->_vec_score.push_back(p->_winlose_score);
		}

		packet["players"][i]["score"] = p->_score;
		packet["players"][i]["cur_end_flag"] = p->_cur_end_flag;
		packet["players"][i]["cur_pao_flag"] = p->_cur_pao_flag;

		if (_end_type == ET_HUANG_ZHUANG)
		{
			packet["players"][i]["card_type"] = CARD_TYPE_ERROR;
		}
		else
		{
			packet["players"][i]["card_type"] = p->_card_type;
		}
		packet["players"][i]["fangpaiji_num"] = p->_fangpaiji_num;
		packet["players"][i]["gudingji_num_hole"] = p->_gudingji_num_hole;
		packet["players"][i]["gudingji_num_out"] = p->_gudingji_num_out;
		packet["players"][i]["chongfengji_num"] = p->_chongfengji_num;
		packet["players"][i]["gold"] = p->_gold;
		packet["players"][i]["diamonds"] = p->_diamonds;
		packet["players"][i]["paiwei_score"] = p->_paiwei_score;

		int if_banker = (p->_seatid == _banker_seat) ? 1 : 0;
		packet["players"][i]["if_banker"] = if_banker;

		std::string hole_str;
		for (unsigned int j = 0; j < p->_hole_mjs.mjs.size(); j++)
		{
			packet["players"][i]["_hole_mjs"].append(p->_hole_mjs.mjs[j].val);
			hole_str += i2str(p->_hole_mjs.mjs[j].val);
			if (j < p->_hole_mjs.mjs.size() - 1)
			{
				hole_str += ",";
			}
		}
		if (p->_hole_mjs.mjs.size() == 0)
		{
			packet["players"][i]["_hole_mjs"].resize(0);
		}

		std::string fm_str;
		for (unsigned int j = 0; j < p->_form_mjs.form_mjz.size(); j++)
		{
			MJZ mjz = p->_form_mjs.form_mjz[j];
			packet["players"][i]["_form_mjs"][j]["zu_type"] = mjz.zu_type;
			packet["players"][i]["_form_mjs"][j]["from_seat"] = mjz.from_seat;
			fm_str += i2str(mjz.zu_type);
			fm_str += ":";
			for (unsigned int k = 0; k < mjz.zu_mjs.size(); k++)
			{
				packet["players"][i]["_form_mjs"][j]["zu_mjs"].append(mjz.zu_mjs[k].val);
				fm_str += i2str(mjz.zu_mjs[k].val);
				if (k < mjz.zu_mjs.size() - 1)
				{
					fm_str += ",";
				}
			}
			if (j < p->_form_mjs.form_mjz.size() - 1)
			{
				fm_str += "|";
			}
		}
		std::string out_str;
		for (unsigned int j = 0; j < p->_out_mjs.mjs.size(); j++)
		{
			packet["players"][i]["_out_mjs"].append(p->_out_mjs.mjs[j].val);
			out_str += i2str(p->_out_mjs.mjs[j].val);
			if (j < p->_out_mjs.mjs.size() - 1)
			{
				out_str += ",";
			}
		}

		if (p->_out_mjs.mjs.size() == 0)
		{
			packet["players"][i]["_out_mjs"].resize(0);
		}

		if (YXJMJ_SERVER._game_flag < 1000000)
		{
			game_sql::insert_board_end_record(
				_rec_id,
				_roomid,
				_board_choose,
				_board_choose - _rest_board,
				_player_num,
				time_str,
				_end_type,
				_fangpaiji_mj.val,
				_fangpaiji_mj.next_fangpai_mj().val,
				p->_uid,
				p->_nick_name,
				p->_seatid,
				if_banker,
				p->_jiaopai_flag,
				p->_cur_gang_score,
				p->_cur_angang_score,
				p->_cur_minggang_score,
				p->_cur_fanggang_score,
				p->_fangpaiji_score,
				p->_gudingji_score,
				p->_chongfengji_score,
				p->_zherenji_score,
				p->_cardtype_score,
				p->_winlose_score,
				p->_score,
				p->_cur_pao_flag,
				p->_card_type,
				p->_fangpaiji_num,
				hole_str,
				fm_str,
				out_str
			);
		}

		i++;
	}
	//统计服务器当天游戏数量
	string date = general_date_str();
	game_sql::increase_add_action(YXJMJ_SERVER._server_id, date);

	if (YXJMJ_SERVER._game_flag < 1000000)
	{
		int end_board = _board_choose - _rest_board;
		if (_rec_id > 0 && _player_num == 2)
		{
			game_sql::update_total_end_record(_rec_id, end_board, time_str
				, _seats[0]._player->_score
				, _seats[1]._player->_score);
		}
		else if (_rec_id > 0 && _player_num == 3)
		{
			game_sql::update_total_end_record(_rec_id, end_board, time_str
				, _seats[0]._player->_score
				, _seats[1]._player->_score
				, _seats[2]._player->_score);
		}
		else if (_rec_id > 0 && _player_num == 4)
		{
			game_sql::update_total_end_record(_rec_id, end_board, time_str
				, _seats[0]._player->_score
				, _seats[1]._player->_score
				, _seats[2]._player->_score
				, _seats[3]._player->_score);
		}
	}
	//_result_flash_timer.start();
	int end_sec = 12;
	if (YXJMJ_SERVER._game_flag / 1000000 == 3 && _rest_board == 0 && _match_id != 0)
	{
		packet["quick_match_info"] = calculate_quickly_match();
		end_sec = 60;
	}
	RunOnce(_end_flash_timer, end_sec, [this]() {
		GAME_LOG.debug("end_flash_timer_out.\n");
		start_ready();
	});
	GAME_LOG.debug("SERVER_GAME_END_BC.\n");
	
	broadcast(NULL, packet);
	return 0;
}

int Room::getin_mj(Player *cur_player, int type)
{
	Mj mj;
	//没有牌了的荒庄处理
	if (!_comm_mjs.pop_mj(mj))
	{
		GAME_LOG.info("comm mjs, has no more mj.\n");
		do_huangzhuang();
		game_end(1);
		return 1;
	}

	cur_player->_hole_mjs.add_mj(mj);
	cur_player->_mo_mj = mj;
	cur_player->_mo_cnt++;
	cur_player->_guo_shou_bu_hu_flag = 0;

	//刷新各个用户的状态
	cur_player->_status = INPLAY_AFTER_GETIN_MJ;
	std::map<int, Player*>::iterator it;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		if (p == cur_player) continue;
		p->_status = INPlAY;
	}

	if (type == 1) _gang_mo_cnt++;

	//广播摸到的牌？
	JsonPacket packet;
	packet["cmd"] = SERVER_GET_ONE_MJ;
	packet["uid"] = cur_player->_uid;
	packet["seatid"] = cur_player->_seatid;
	packet["roomid"] = _roomid;
	packet["rest_mjs"] = _comm_mjs.count();
	packet["mj"] = mj.val;
	packet["mo_type"] = type;
	packet["expire"] = 15;
	GAME_LOG.debug("SERVER_GET_ONE_MJ.\n");
	
	broadcast(NULL, packet);
	//摸牌之后的判断
	operate_check_after_getin_mj(cur_player);
	return 0;
}

int Room::operate_check_after_getin_mj(Player *cur_player)
{
	//这个时候是在用户摸得一张牌之后的判断	
	int ming_gang_flag = 0;
	int an_gang_flag = 0;
	std::vector<int> vec_gang_mj;
	int ting_flag = 0;
	std::vector<int> vec_ting_mj;
	int zi_mo_hu_flag = 0;

	zi_mo_hu_flag = (int)(check_zi_mo_hu(cur_player));
	//如果没有报听，检查以下操作
	if (cur_player->_cur_baoting_flag == 0)
	{
		ming_gang_flag = (int)(check_ming_gang(cur_player, cur_player->_mo_mj));
		an_gang_flag = (int)(check_ang_gang(cur_player, vec_gang_mj));
		ting_flag = (int)(check_op_ting(cur_player, vec_ting_mj));
	}

	//如果玩家已经听牌，无法自摸，就老老实实打掉摸到的牌
	if ((cur_player->_cur_baoting_flag == 1
		|| cur_player->_cur_baoting_flag == 2)
		&& !zi_mo_hu_flag)
	{
		cur_player->_auto_outmj_timer.start(); //定时器，延时一秒出
		return 0;
	}
	//机器人代打
	if (cur_player->_robot_op == 1)
	{
		cur_player->_auto_outmj_timer.start();
		return 0;
	}

	//告诉这个刚摸了牌的用户 他可以进行哪些操作
	JsonPacket packet;
	packet["cmd"] = SERVER_OPERATE_CHECK_AFTER_GETIN_MJ;
	packet["uid"] = cur_player->_uid;
	packet["seatid"] = cur_player->_seatid;
	packet["roomid"] = _roomid;
	packet["ming_gang_flag"] = ming_gang_flag;
	packet["getin_mj"] = cur_player->_mo_mj.val;
	packet["an_gang_flag"] = an_gang_flag;
	packet["zi_mo_hu_flag"] = zi_mo_hu_flag;
	packet["ting_flag"] = ting_flag;

	if (an_gang_flag != 0)
	{
		for (unsigned int i = 0; i<vec_gang_mj.size(); i++)
		{
			packet["an_gang_mj_choose"].append(vec_gang_mj[i]);
		}
	}

	if (ting_flag != 0)
	{
		for (unsigned int i = 0; i<vec_ting_mj.size(); i++)
		{
			packet["ting_mj_choose"].append(vec_ting_mj[i]);
		}
	}

	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_GETIN_MJ.\n");
	
	unicast(cur_player, packet);

	if (_has_timer)
	{
		_cur_getin_player = cur_player;
		_cur_getin_mj = cur_player->_mo_mj;
		cur_player->_getin_outmj_timer.start();
	}


	return 0;

}

int Room::operate_check_after_peng_mj(Player *player)
{
	int an_gang_flag = 0;

	std::vector<int> vec_gang_val;
	if (check_ang_gang(player, vec_gang_val))
	{
		an_gang_flag = 1;
	}
	JsonPacket packet;
	packet["cmd"] = SERVER_OPERATE_CHECK_AFTER_PENG;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["an_gang_flag"] = an_gang_flag;

	if (an_gang_flag == 1)
	{
		for (unsigned int i = 0; i<vec_gang_val.size(); i++)
		{
			packet["an_gang_mj_choose"].append(vec_gang_val[i]);
		}
	}
	GAME_LOG.debug("SERVER_OPERATE_CHECK_AFTER_PENG.\n");
	
	unicast(player, packet);

	if (_has_timer)
	{
		player->_getin_outmj_timer.start();
	}
	return 0;
}


int Room::operate_check_qiang_gang_hu(Mj gang_mj, Player* gang_player)
{
	int ret = 0;
	for (int i = 0; i < _player_num - 1; i++)
	{
		int flag = check_qiang_gang_hu(_m_check_qgh[i]._player, gang_mj, gang_player);
		_m_check_qgh[i]._qianggang_hu_flag = flag;
		if (!flag)
		{
			_m_check_qgh[i]._player_operation = OP_PASS;
		}
		else
		{
			//通知用户可以抢杠胡
			send_bar_operate_check_qiang_gang_hu(_m_check_qgh[i]._player, gang_mj);
			_m_check_qgh[i]._player->_qiangganghu_timer.start();
			ret = 1;
		}
	}
	return ret;
}

int Room::operate_check_after_putout_mj(Mj out_mj, Player *out_mj_player)
{
	//初始化打出牌的玩家可操作检测结构体
	_m_check[0].clear();
	_m_check[1].clear();
	_m_check[2].clear();

	Player* cur_p = _cur_outmj_player;
	for (int i(0); i < (_player_num - 1); i++)
	{
		cur_p = next_player(cur_p);
		_m_check[i].clear();
		_m_check[i]._player = cur_p;
	}


	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._player == NULL) continue;

		_m_check[i]._fangpao_hu_flag = check_fang_pao_hu(_m_check[i]._player, out_mj, out_mj_player);
		//如果报听，不能再碰杠
		if (_m_check[i]._player->_cur_baoting_flag != 0)
		{
			_m_check[i]._fang_gang_flag = 0;
			_m_check[i]._peng_flag = 0;
		}
		else
		{
			_m_check[i]._fang_gang_flag = check_fang_gang(_m_check[i]._player, out_mj);
			_m_check[i]._peng_flag = check_peng(_m_check[i]._player, out_mj);
		}
		GAME_LOG.debug("player[%d], _fangpao_hu_flag:%d, _fang_gang_flag:%d, _peng_flag:%d.\n", _m_check[i]._player->_uid, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);

		//没有可操作的直接置位PASS

		if (_m_check[i]._player->_robot_op == 1)
		{
			_m_check[i]._fangpao_hu_flag = false;
			_m_check[i]._fang_gang_flag = false;
			_m_check[i]._peng_flag = false;
		}

		if (!_m_check[i]._fangpao_hu_flag && !_m_check[i]._fang_gang_flag && !_m_check[i]._peng_flag)
		{
			_m_check[i]._player_operation = OP_PASS;
			GAME_LOG.debug("pass.\n");
		}

	}

	bool has_hu = false;
	bool has_gang = false;
	bool has_peng = false;

	int hu_num = 0;
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag) hu_num++;
	}

	//先看有没有能胡的。
	for (int i = 0; i < _player_num - 1; i++)
	{
		if (_m_check[i]._fangpao_hu_flag)
		{
			//如果只有他一个人可以胡
			if (hu_num <= 1)
			{
				send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);
				_m_check[i]._player->_pass_timer.start();
				has_hu = true;
				break;
			}
			else if (hu_num > 1)
			{
				//如果多人可以胡
				send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, 0, 0);
				_m_check[i]._player->_pass_timer.start();
				has_hu = true;
			}
		}
	}

	if (!has_hu)
	{
		for (int i = 0; i < _player_num - 1; i++)
		{
			if (_m_check[i]._fang_gang_flag)
			{
				send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);
				_m_check[i]._player->_pass_timer.start();
				has_gang = true;
				has_peng = true;
				break;
			}
		}
	}

	if (!has_hu && !has_gang)
	{
		for (int i = 0; i < _player_num - 1; i++)
		{
			if (_m_check[i]._peng_flag)
			{
				send_bar_operate_check_after_putout_mj(_m_check[i]._player, _m_check[i]._fangpao_hu_flag, _m_check[i]._fang_gang_flag, _m_check[i]._peng_flag);
				_m_check[i]._player->_pass_timer.start();
				has_peng = true;
				break;
			}
		}
	}

	if (!has_hu && !has_gang && !has_peng)
	{

		_cur_seat = next_seat(_cur_seat);
		Player *player = _seats[_cur_seat]._player;
		//没人要的牌 变成冲锋鸡
		//冲锋鸡
		if (_cur_outmj.val == S1 && _chongfengji_player == NULL && _zherenji_from_player == NULL)
		{
			_chongfengji_player = _cur_outmj_player;
			JsonPacket packet;
			packet["cmd"] = SERVER_CHONG_FENG_JI_BC;
			packet["uid"] = _chongfengji_player->_uid;
			packet["seatid"] = _chongfengji_player->_seatid;
			GAME_LOG.debug("SERVER_CHONG_FENG_JI_BC.\n");
			
			broadcast(NULL, packet);
		}

		_gang_shang_pao_check_flag = 0;
		getin_mj(player);
	}

	return 0;
}

int Room::send_bar_operate_check_after_putout_mj(Player *player, int fangpaohu_flag, int _fang_gang_flag, int _peng_flag)
{
	JsonPacket packet;
	packet["cmd"] = SERVER_OPERATE_CHECK_OTHERS_PUTOUT_MJ;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	packet["fang_pao_hu_flag"] = fangpaohu_flag;
	packet["_fang_gang_flag"] = _fang_gang_flag;
	packet["_peng_flag"] = _peng_flag;
	GAME_LOG.debug("SERVER_OPERATE_CHECK_OTHERS_PUTOUT_MJ.\n");
	
	unicast(player, packet);

	return 0;
}

int Room::send_bar_operate_check_qiang_gang_hu(Player *player, Mj gang_mj)
{
	JsonPacket packet;
	packet["cmd"] = SERVER_OPERATE_CHECK_QIANG_GANG_HU;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	packet["qgh_mj"] = gang_mj.val;
	GAME_LOG.debug("SERVER_OPERATE_CHECK_QIANG_GANG_HU.\n");
	
	unicast(player, packet);
	return 0;
}

void Room::vector_to_json_array(std::vector<Mj> &mjs, JsonPacket &packet, string key)
{
	for (unsigned int i = 0; i < mjs.size(); i++)
	{
		packet[key].append(mjs[i].val);
	}
	if (mjs.size() == 0)
	{
		packet[key].resize(0);
	}
}

void Room::form_player_all_mj_info_json(Player *player, JsonPacket &packet, string key)
{
	Json::Value zu_mjs;
	Json::Value _out_mjs;
	Json::Value _hole_mjs;

	for (unsigned int i = 0; i<player->_hole_mjs.mjs.size(); i++)
	{
		packet[key]["_hole_mjs"].append(player->_hole_mjs.mjs[i].val);
	}
	if (player->_hole_mjs.mjs.size() == 0)
	{
		packet[key]["_hole_mjs"].resize(0);
	}
	for (unsigned int i = 0; i<player->_out_mjs.mjs.size(); i++)
	{
		packet[key]["_out_mjs"].append(player->_out_mjs.mjs[i].val);
	}
	if (player->_out_mjs.mjs.size() == 0)
	{
		packet[key]["_out_mjs"].resize(0);
	}

	for (unsigned int i = 0; i< player->_form_mjs.form_mjz.size(); i++)
	{
		MJZ mjz = player->_form_mjs.form_mjz[i];
		packet[key]["_form_mjs"][i]["zu_type"] = mjz.zu_type;
		packet[key]["_form_mjs"][i]["from_seat"] = mjz.from_seat;

		for (unsigned int j = 0; j<mjz.zu_mjs.size(); j++)
		{
			packet[key]["_form_mjs"][i]["zu_mjs"].append(mjz.zu_mjs[j].val);
		}
	}
	if (player->_form_mjs.form_mjz.size() == 0)
	{
		packet[key]["_form_mjs"].resize(0);
	}
}


int Room::next_seat(int pos)
{
	for (int i = 0; i < _player_num - 1; i++)
	{
		pos++; if (pos >= _player_num) pos = 0;
		return pos;
	}
	return -1;
}


Player *Room::next_player(Player *player)
{

	int seat = player->_seatid;
	int n_seat = next_seat(seat);
	Player *n_player = _seats[n_seat]._player;
	if (n_player != NULL)
	{
		return n_player;
	}
	else
	{
		GAME_LOG.fatal("function next_player, next_player = NULL.\n");
		return NULL;
	}
}

Player *Room::next_jiaopai_player(Player *player)
{

	int seat = player->_seatid;
	int n_seat = next_seat(seat);
	Player *n_player = _seats[n_seat]._player;
	if (n_player != NULL && n_player->_jiaopai_flag == 1)
	{
		return n_player;
	}
	else
	{
		GAME_LOG.fatal("function next_jiaopai_player, next_player = NULL.\n");
		return NULL;
	}
}


int Room::del_player(int uid)
{
	auto itr = _players.find(uid);
	if (itr != _players.end())
	{
		GAME_LOG.error("del player in room[%d], player[%d], not int _players.\n", _roomid, uid);
		return -1;
	}
	if (YXJMJ_SERVER._game_flag > 1000000)
	{
		handler_logout(itr->second,NULL);
	}
	stand_up(itr->second);
	delete itr->second;
	_players.erase(uid);
	YXJMJ_SERVER.PlayerLeaveRoom(uid);
	return 0;
}

void Room::del_all_players()
{
	Player *player;
	//原map会释放 迭代器会失效
	std::map<int, Player*> tmp = _players;
	for (auto& info : tmp)
	{
		del_player(info.first);
	}
	GAME_LOG.info("delete room[%d] all players succ.\n", _roomid);
	stopalltimer();
}

int Room::unicast(Player *p, JsonPacket &packet)
{
	int fd = YXJMJ_SERVER.Find<UID_KEY>(p->_uid);
	auto session = YXJMJ_SERVER[fd];
	session->Send(packet.Encode());
	return 0;
}

int Room::broadcast(Player *p, JsonPacket &packet)
{
	for (auto& info : _players)
	{
		auto player = info.second;
		if (p == player)
		{
			continue;
		}
		unicast(player, packet);
	}
	return 0;
}

int Room::handler_rebind(Player *player)
{
	GAME_LOG.info("handler_rebind. player[%d]. roomid[%d], state[%d].\n", player->_uid, player->_roomid, _state);
	//刷新玩家状态和刷新房间人数

	//如果游戏已经要结束了 还要重连
	if (_state == STATE_END)
	{
		GAME_LOG.info("handler_rebind fail, Because state is STATE_END. player[%d]. roomid[%d], state[%d].\n", player->_uid, player->_roomid, _state);
		del_player(player->_uid);
		return 0;
	}

	if (game_sql::update_db_player_online(player->_uid, YXJMJ_SERVER._server_id, player->_roomid, 1) < 0)
	{
		GAME_LOG.fatal("handler_rebind, update db error.\n");
	}


	player->_online = 1;

	JsonPacket packet;
	packet["cmd"] = SERVER_REBIND_UC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = player->_roomid;
	packet["room_pwd"] = _password;
	packet["state"] = _state;
	packet["do_dissolution"] = if_dissolution();
	packet["board_choose"] = _board_choose;
	packet["rest_board"] = _rest_board;
	packet["player_num"] = _player_num;
	packet["gang_mo_cnt"] = _gang_mo_cnt;
	packet["clubid"] = _clubid;
	packet["priv_uid"] = _priv_uid;
	packet["rest_mjs"] = _comm_mjs.count();
	packet["cur_seat"] = _cur_seat;

	packet["game_flag"] = YXJMJ_SERVER._game_flag;
	if (YXJMJ_SERVER._game_flag < 1000000) {
		packet["base_gold"] = _base_gold;
	}

	if (_state == STATE_PLAYING)
	{
		packet["rest_mjs"] = _comm_mjs.count();
		if (_chongfengji_player == NULL)
		{
			packet["chongfengji_seatid"] = -1;
		}
		else
		{
			packet["chongfengji_seatid"] = _chongfengji_player->_seatid;
		}
	}
	if (_state > STATE_READY)
	{
		packet["banker_seatid"] = _banker_seat;
		packet["dice"].append(_dice[0]);
		packet["dice"].append(_dice[1]);
	}

	std::map<int, Player*>::iterator it;
	int i = 0;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *p = it->second;
		packet["players"][i]["uid"] = p->_uid;
		packet["players"][i]["seatid"] = p->_seatid;
		packet["players"][i]["nick_name"] = p->_nick_name;
		packet["players"][i]["avater_url"] = p->_avater_url;
		packet["players"][i]["login_ip"] = p->_login_ip;
		packet["players"][i]["score"] = p->_score;
		packet["players"][i]["sex"] = p->_sex;
		packet["players"][i]["gold"] = p->_gold;
		packet["players"][i]["diamonds"] = p->_diamonds;
		packet["players"][i]["status"] = p->_status;
		packet["players"][i]["online"] = p->_online;
		packet["players"][i]["agree_dissroom"] = p->_agree_dissroom;
		packet["players"][i]["dq_val"] = p->_dq_val;
		packet["players"][i]["cur_baoting_flag"] = p->_cur_baoting_flag;
		packet["players"][i]["robot_opt"] = p->_robot_op;
		packet["players"][i]["paiwei_score"] = p->_paiwei_score;
		packet["players"][i]["vip_level"] = p->_vip_level;

		if (_state > STATE_READY)
		{
			//手上的麻将
			for (unsigned int j = 0; j<p->_hole_mjs.mjs.size(); j++)
			{
				packet["players"][i]["_hole_mjs"].append(p->_hole_mjs.mjs[j].val);
			}
			if (p->_hole_mjs.mjs.size() == 0)
			{
				packet["players"][i]["_hole_mjs"].resize(0);
			}
			//打出去的麻将
			for (unsigned int j = 0; j<p->_out_mjs.mjs.size(); j++)
			{
				packet["players"][i]["_out_mjs"].append(p->_out_mjs.mjs[j].val);
			}
			if (p->_out_mjs.mjs.size() == 0)
			{
				packet["players"][i]["_out_mjs"].resize(0);
			}
			//组成组的麻将
			for (unsigned int j = 0; j< p->_form_mjs.form_mjz.size(); j++)
			{
				MJZ mjz = p->_form_mjs.form_mjz[j];
				packet["players"][i]["_form_mjs"][j]["zu_type"] = mjz.zu_type;
				packet["players"][i]["_form_mjs"][j]["from_seat"] = mjz.from_seat;

				for (unsigned int k = 0; k<mjz.zu_mjs.size(); k++)
				{
					packet["players"][i]["_form_mjs"][j]["zu_mjs"].append(mjz.zu_mjs[k].val);
				}
			}
			if (p->_form_mjs.form_mjz.size() == 0)
			{
				packet["players"][i]["_form_mjs"].resize(0);
			}
		}
		i++;
	}
	GAME_LOG.debug("SERVER_REBIND_UC.\n");
	
	unicast(player, packet);
	GAME_LOG.debug("aaaa.\n");
	//定缺广播
	if (_state == STATE_DING_QUE && player->_dq_val == 0)
	{
		JsonPacket packet;
		packet["cmd"] = SERVER_DINGQUE_STARGE_BC;
		packet["roomid"] = _roomid;
		
		unicast(player, packet);
	}
	//轮到当前用户操作
	else if (player->_status == INPLAY_AFTER_GETIN_MJ && player->_seatid == _cur_seat)
	{
		GAME_LOG.debug("bbbb.\n");
		operate_check_after_getin_mj(player);
	}
	else if (player->_status == INPLAY_AFTER_PENG_MJ && player->_seatid == _cur_seat)
	{
		GAME_LOG.debug("cccc.\n");
		operate_check_after_peng_mj(player);
	}
	return 0;
}



int Room::send_all_end_info()
{
	JsonPacket packet;
	packet["cmd"] = SERVER_GAME_ALL_END_BC;
	packet["roomid"] = _roomid;
	packet["board_choose"] = _board_choose;
	int end_board = _board_choose - _rest_board;
	packet["end_board"] = end_board;
	std::string time_str = general_time_str();
	packet["time_str"] = time_str.c_str();
	std::map<int, Player*>::iterator it;
	int i = 0;
	for (it = _players.begin(); it != _players.end(); it++)
	{
		Player *player = it->second;
		packet["players"][i]["uid"] = player->_uid;
		packet["players"][i]["avater_url"] = player->_avater_url;
		packet["players"][i]["nick_name"] = player->_nick_name;
		packet["players"][i]["zimo_times"] = player->_zimo_times;
		packet["players"][i]["jiepao_times"] = player->_jiepao_times;
		packet["players"][i]["dianpao_times"] = player->_dianpao_times;
		packet["players"][i]["anggang_times"] = player->_anggang_times;
		packet["players"][i]["minggang_times"] = player->_minggang_times;
		for (unsigned int j = 0; j<player->_vec_score.size(); j++)
		{
			packet["players"][i]["score_arr"].append(player->_vec_score[j]);
		}
		packet["players"][i]["total_score"] = player->_score;
		i++;
	}
	
	GAME_LOG.info("SERVER_GAME_ALL_END_BC.\n");
	broadcast(NULL, packet);
	return 0;
}

int Room::handler_nolmal_chart_req(Player *player, NetworkSessionBase* session)
{
	JsonPacket& jpacket = session->_jpacket;
	JsonPacket packet;
	int type = JsonTo<int>(jpacket["type"]);
	packet["cmd"] = SERVER_NOLMAL_CHAT_BC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["nick_name"] = player->_nick_name;
	packet["roomid"] = _roomid;
	packet["type"] = type;
	if (type == 3)
	{
		std::string msg = JsonTo<string>(jpacket["message"]);
		//std::string out_msg = filter(yxjmj.v_words, msg);
		packet["message"] = msg;
	}
	else if (type == 1 || type == 2)
	{
		packet["tag"] = jpacket["tag"];
	}
	GAME_LOG.info("SERVER_NOLMAL_CHAT_BC.\n");
	
	broadcast(NULL, packet);
	return 0;
}

int Room::handler_speak_req(Player *player, NetworkSessionBase* session)
{
	JsonPacket& jpacket = session->_jpacket;
	JsonPacket packet;
	packet["cmd"] = SERVER_SPEAK_BC;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["roomid"] = _roomid;
	packet["time_sec"] = jpacket["time_sec"];
	packet["sound_url"] = jpacket["sound_url"];
	
	GAME_LOG.info("SERVER_SPEAK_BC.\n");
	broadcast(NULL, packet);
	return 0;
}

int Room::handler_del_player(Player * player, NetworkSessionBase* session)
{
	if (_state != STATE_READY)
	{
		GAME_LOG.debug("you can't exit a running game, because _state != STATE_READY\n");
		return -1;
	}
	if (YXJMJ_SERVER._game_flag / 1000000 == 3 && _rest_board != _board_choose)
	{
		GAME_LOG.debug("you can't exit a running game\n");
		return -1;
	}
	return del_player(player->_uid);
}


void Room::begin_robot_op_bc(Player *player)
{
	JsonPacket packet;
	packet["cmd"] = SERVER_BEGIN_ROBOT_OP_BC;
	packet["uid"] = player->_uid;
	packet["roomid"] = player->_roomid;
	packet["seatid"] = player->_seatid;
	
	GAME_LOG.debug("SERVER_BEGIN_ROBOT_OP_BC.\n");
	broadcast(NULL, packet);
}


bool Room::if_que_men(Player *player, const Mj &mj)
{
	if (_player_num == 4)
	{
		return false;
	}

	if (mj.val / 10 == player->_dq_val)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool Room::check_peng(Player *player, Mj out_mj)
{
	if (if_que_men(player, out_mj))
	{
		return false;
	}

	int ret = player->_hole_mjs.peng_and_gang(out_mj);
	if (ret == 1 || ret == 2)
	{
		return true;
	}
	else
	{
		return false;
	}
}
bool Room::check_fang_gang(Player* player, Mj out_mj)
{
	if (if_que_men(player, out_mj))
	{
		return false;
	}

	if (player->_hole_mjs.peng_and_gang(out_mj) == 2)
	{
		if (_comm_mjs.count() == 0) //最后一张打出去的牌不能杠
		{
			return false;
		}
		else
		{
			return true;
		}
	}
	else
	{
		return false;
	}
}

bool Room::check_fang_pao_hu(Player *player, Mj out_mj, Player *out_mj_player)
{
	if (if_que_men(player, out_mj))
	{
		return false;
	}
	std::vector<Mj> temp_mjs;
	temp_mjs = player->_hole_mjs.mjs;
	temp_mjs.push_back(out_mj);
	bool ret = check_hupai(temp_mjs, player->_dq_val);
	if (!ret)
	{
		return false;
	}

	if (player->_guo_shou_bu_hu_flag == 1)
	{
		GAME_LOG.debug("guo shou can not hu.\n");
		return false;
	}

	//是否地胡
	if (_comm_mjs.count() == 108 - _player_num * 13 - 1)
	{
		return true;
	}

	//玩家在有“豆”的情况下允许点胡。大胡有豆无豆皆可胡牌。
	if (player->_have_gang == 1)
	{
		return true;
	}

	if (_gang_shang_pao_check_flag)
	{
		return true;
	}

	//计算是否是大胡
	player->_hole_mjs.mjs.push_back(out_mj);
	int cardtype = calculate_card_type(player);
	player->_hole_mjs.mjs.pop_back();
	if (cardtype <= 1)
	{
		return false;
	}

	return true;
}

bool Room::check_qiang_gang_hu(Player *player, Mj gang_mj, Player *qiang_gang_player)
{
	if (if_que_men(player, gang_mj))
	{
		return false;
	}
	std::vector<Mj> temp_mjs;
	temp_mjs = player->_hole_mjs.mjs;
	temp_mjs.push_back(gang_mj);
	bool ret = check_hupai(temp_mjs, player->_dq_val);
	return ret;
}

//自摸牌后
//有无暗杠
bool Room::check_ang_gang(Player *player, std::vector<int> &vec_gang_val)
{
	//最多14张牌
	unsigned int i_num = player->_hole_mjs.mjs.size();
	if (i_num > 14)
	{
		return false;
	}
	//牌数应为3n+2
	if (i_num % 3 != 2)
	{
		return false;
	}
	if (_comm_mjs.count() == 0) //只剩最后一张牌不能暗杠了
	{
		return false;
	}

	return player->_hole_mjs.check_four_same(vec_gang_val, player->_dq_val);
}

bool Room::check_op_ting(Player *player, std::vector<int> &vec_ting_mjval)
{
	//必须14张牌
	unsigned int i_num = player->_hole_mjs.mjs.size();
	if (i_num != 14)
	{
		return false;
	}
	//必须首次摸牌
	//1，如果庄家首次摸牌，天听
	if (player->_seatid == _banker_seat && player->_mo_cnt == 1)
	{
		if (check_baoting(player->_hole_mjs.mjs, vec_ting_mjval, player->_dq_val))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	//2, 非庄家，首次摸牌, 地听
	else if (player->_seatid != _banker_seat && player->_mo_cnt == 1)
	{
		if (check_baoting(player->_hole_mjs.mjs, vec_ting_mjval, player->_dq_val))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	return false;
}


//检查能否暗杠某张麻将牌
bool Room::check_ang_gang(Player* player, Mj mj)
{
	//最多14张牌
	unsigned int i_num = player->_hole_mjs.mjs.size();
	if (i_num > 14)
	{
		return false;
	}
	//牌数应为3n+2
	if (i_num % 3 != 2)
	{
		return false;
	}
	if (_comm_mjs.count() == 0) //只剩最后一张牌不能暗杠了
	{
		return false;
	}

	//有缺门的牌
	if (if_que_men(player, mj))
	{
		return false;
	}

	if (player->_hole_mjs.peng_and_gang(mj) == 3)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//看摸得的那张牌能否明杠
bool Room::check_ming_gang(Player* player, Mj mj)
{
	if (if_que_men(player, mj))
	{
		return false;
	}
	if (_comm_mjs.count() == 0) //只剩最后一张牌不能明杠
	{
		return false;
	}
	return player->_form_mjs.check_same_ke_mj(mj);
}

//检查能否自摸胡牌
bool Room::check_zi_mo_hu(Player* player)
{
	//有缺门的牌
	if (_player_num != 4 && player->_hole_mjs.has_que_men(player->_dq_val))
	{
		return false;
	}

	bool ret = check_hupai(player->_hole_mjs.mjs, player->_dq_val);
	if (!ret)
	{
		return false;
	}
	return  true;
}

//计算是否叫牌
int Room::check_jiaopai_flag(Player *player)
{
	if (player->_hole_mjs.mjs.size() % 3 == 2) //3N+2张牌，必须是胡牌了
	{
		if (check_hupai(player->_hole_mjs.mjs, player->_dq_val))
		{
			player->_jiaopai_flag = 1;
		}
		else
		{
			player->_jiaopai_flag = 0;
		}
	}
	else if (player->_hole_mjs.mjs.size() % 3 == 1) //3N+1张牌，必须听牌
	{
		if (check_ting(player->_hole_mjs.mjs, player->_dq_val))
		{
			player->_jiaopai_flag = 1;
		}
		else
		{
			player->_jiaopai_flag = 0;
		}
	}
	else
	{
		player->_jiaopai_flag = 0;
	}

	return player->_jiaopai_flag;
}


//碰
int Room::do_peng(Player *player, Player * out_player, Mj out_mj)
{
	if (!check_peng(player, out_mj))
	{
		GAME_LOG.error("can not peng, player[%d].\n", player->_uid);
		return -1;
	}
	out_player->_out_mjs.remove_back_mj();
	remove_n_mj(player->_hole_mjs.mjs, out_mj, 2);
	player->_form_mjs.add_form(PENG, out_mj, out_player->_seatid);
	return 0;
}

//放杠
int Room::do_fang_gang(Player *player, Player * out_player, Mj out_mj)
{
	if (!check_fang_gang(player, out_mj))
	{
		GAME_LOG.error("can not fang gang mj[%d]. player[%d].\n", out_mj.val, player->_uid);
		return -1;
	}

	out_player->_out_mjs.remove_back_mj();
	remove_n_mj(player->_hole_mjs.mjs, out_mj, 3);
	player->_form_mjs.add_form(FANG_GANG, out_mj, out_player->_seatid);
	player->_have_gang = 1;

	return 0;
}

//暗杠
int Room::do_ang_gang(Player *player, Mj mj)
{
	if (!check_ang_gang(player, mj))
	{
		GAME_LOG.error("can not ang gang mj[%d]. player[%d].\n", mj.val, player->_uid);
		return -1;
	}

	remove_n_mj(player->_hole_mjs.mjs, mj, 4);
	player->_form_mjs.add_form(ANG_GANG, mj, player->_seatid);
	player->_anggang_times++;
	player->_have_gang = 1;
	return 0;
}

//明杠
int Room::do_ming_gang(Player *player, Mj mj)
{
	if (!check_ming_gang(player, mj))
	{
		GAME_LOG.error("can not ming gang mj[%d]. player[%d].\n", mj.val, player->_uid);
		return -1;
	}
	remove_n_mj(player->_hole_mjs.mjs, mj, 1);
	player->_form_mjs.add_form(MING_GANG, mj);
	player->_minggang_times++;
	player->_have_gang = 1;
	return 0;
}

//出牌
// int Room::do_out_mj(Player *player, Mj mj)
// {
// 	remove_n_mj( player->_hole_mjs.mjs, mj, 1);
// 	player->_out_mjs.add_mj(mj);
// 	return 0;
// }



int Room::handler_logout(Player *player, NetworkSessionBase* session)
{
	JsonPacket packet;
	packet["cmd"] = SERVER_GOLDROOM_LOGOUT_ROOM;
	packet["uid"] = player->_uid;
	packet["seatid"] = player->_seatid;
	packet["type"] = player->_logout_type;
	GAME_LOG.debug("SERVER_LOGOUT_BC\n");
	broadcast(NULL, packet);
	return 0;
}

int Room::handler_cancel_robot_op(Player *player, NetworkSessionBase* session)
{

	player->_robot_op = 0;
	JsonPacket packet;
	packet["cmd"] = SERVER_CANCEL_ROBOT_OP_SUCC_BC;
	packet["uid"] = player->_uid;
	packet["roomid"] = player->_roomid;
	packet["seatid"] = player->_seatid;
	
	GAME_LOG.debug("SERVER_CANCEL_ROBOT_OP_SUCC_BC.\n");
	broadcast(NULL, packet);
	return 0;
}



